diff --git a/go.mod b/go.mod index 180b9c0ee0e..6201adb8969 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/XSAM/otelsql v0.23.0 github.com/alexedwards/scs/redisstore v0.0.0-20221223131519-238b052508b6 github.com/alexedwards/scs/v2 v2.5.1 - github.com/aws/aws-sdk-go-v2 v1.27.0 + github.com/aws/aws-sdk-go-v2 v1.27.2 github.com/aws/aws-sdk-go-v2/config v1.27.14 github.com/aws/aws-sdk-go-v2/credentials v1.17.14 github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.4.6 @@ -15,7 +15,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/ecr v1.28.1 github.com/aws/aws-sdk-go-v2/service/ecs v1.41.11 github.com/aws/aws-sdk-go-v2/service/rds v1.78.2 - github.com/aws/aws-sdk-go-v2/service/s3 v1.54.1 + github.com/aws/aws-sdk-go-v2/service/s3 v1.55.1 github.com/aws/aws-sdk-go-v2/service/ses v1.22.7 github.com/aws/aws-sdk-go-v2/service/ssm v1.50.2 github.com/aws/aws-sdk-go-v2/service/sts v1.28.8 @@ -25,7 +25,7 @@ require ( github.com/disintegration/imaging v1.6.2 github.com/dustin/go-humanize v1.0.1 github.com/felixge/httpsnoop v1.0.4 - github.com/gabriel-vasile/mimetype v1.4.2 + github.com/gabriel-vasile/mimetype v1.4.3 github.com/go-chi/chi/v5 v5.0.10 github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df github.com/go-logr/zapr v1.3.0 @@ -36,7 +36,7 @@ require ( github.com/go-openapi/strfmt v0.22.0 github.com/go-openapi/swag v0.23.0 github.com/go-openapi/validate v0.23.0 - github.com/go-playground/validator/v10 v10.15.4 + github.com/go-playground/validator/v10 v10.21.0 github.com/go-swagger/go-swagger v0.30.5 github.com/gobuffalo/envy v1.10.2 github.com/gobuffalo/fizz v1.14.4 @@ -135,14 +135,14 @@ require ( github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.2 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.7 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.7 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.9 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.9 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.6 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.9 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.8 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.8 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.6 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.11 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.11 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.9 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.20.7 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.1 // indirect github.com/aymerick/douceur v0.2.0 // indirect @@ -210,7 +210,7 @@ require ( github.com/kr/fs v0.1.0 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect - github.com/leodido/go-urn v1.2.4 // indirect + github.com/leodido/go-urn v1.4.0 // indirect github.com/lithammer/fuzzysearch v1.1.8 // indirect github.com/luna-duclos/instrumentedsql v1.1.3 // indirect github.com/magiconair/properties v1.8.7 // indirect diff --git a/go.sum b/go.sum index 09c6d5f5e7f..bb18706b54c 100644 --- a/go.sum +++ b/go.sum @@ -42,8 +42,8 @@ github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kd github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk= -github.com/aws/aws-sdk-go-v2 v1.27.0 h1:7bZWKoXhzI+mMR/HjdMx8ZCC5+6fY0lS5tr0bbgiLlo= -github.com/aws/aws-sdk-go-v2 v1.27.0/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM= +github.com/aws/aws-sdk-go-v2 v1.27.2 h1:pLsTXqX93rimAOZG2FIYraDQstZaaGVVN4tNw65v0h8= +github.com/aws/aws-sdk-go-v2 v1.27.2/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 h1:x6xsQXGSmW6frevwDA+vi/wqhp1ct18mVXYN08/93to= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2/go.mod h1:lPprDr1e6cJdyYeGXnRaJoP4Md+cDBvi2eOj00BlGmg= github.com/aws/aws-sdk-go-v2/config v1.27.14 h1:QOg8Ud53rrmdjBHX080AaYUBhG2ER28kP/yjE7afF/0= @@ -54,14 +54,14 @@ github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.2 h1:HTAQSEibYaSioHzjOQssUJn github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.2/go.mod h1:NjUtmUEIimOc5tPw//xqKNK/spUqCTSbxjwzCrnsj8U= github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.4.6 h1:oooec6yfvcyH11bYJoCyUyogSW+3OElzkSs1drdBW3A= github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.4.6/go.mod h1:fmGX8e+24AMyHWDj+UnKDHT15Zx14ebJRC1LF0RZjGo= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.7 h1:lf/8VTF2cM+N4SLzaYJERKEWAXq8MOMpZfU6wEPWsPk= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.7/go.mod h1:4SjkU7QiqK2M9oozyMzfZ/23LmUY+h3oFqhdeP5OMiI= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.7 h1:4OYVp0705xu8yjdyoWix0r9wPIRXnIzzOoUpQVHIJ/g= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.7/go.mod h1:vd7ESTEvI76T2Na050gODNmNU7+OyKrIKroYTu4ABiI= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.9 h1:cy8ahBJuhtM8GTTSyOkfy6WVPV1IE+SS5/wfXUYuulw= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.9/go.mod h1:CZBXGLaJnEZI6EVNcPd7a6B5IC5cA/GkRWtu9fp3S6Y= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.9 h1:A4SYk07ef04+vxZToz9LWvAXl9LW0NClpPpMsi31cz0= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.9/go.mod h1:5jJcHuwDagxN+ErjQ3PU3ocf6Ylc/p9x+BLO/+X4iXw= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.6 h1:+/uB/M07Isd7UajQIYW2M4lDc/302gIWu1zMe0d7uKo= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.6/go.mod h1:7Gw/GeEezsEzpU/f1JWzSb1Y4M05taehNadic8jfF8U= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.9 h1:vHyZxoLVOgrI8GqX7OMHLXp4YYoxeEsrjweXKpye+ds= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.9/go.mod h1:z9VXZsWA2BvZNH1dT0ToUYwMu/CR9Skkj/TBX+mceZw= github.com/aws/aws-sdk-go-v2/service/cloudwatchevents v1.23.6 h1:s9TaIFJJ1zVLiKoxvclHNXjcZ+9+JnHvVgWfQgN9srQ= github.com/aws/aws-sdk-go-v2/service/cloudwatchevents v1.23.6/go.mod h1:9h+vJwhl865wjyC7AQOBX4LVQxgntBYrf3p5WtzOSi0= github.com/aws/aws-sdk-go-v2/service/ecr v1.28.1 h1:tfeJG1axeFZX0O5HLOXMyq3W48zLkl5mO/PBccMNTaA= @@ -70,16 +70,16 @@ github.com/aws/aws-sdk-go-v2/service/ecs v1.41.11 h1:/27vG0bgOsJmMqSbjCuF4UdEWZy github.com/aws/aws-sdk-go-v2/service/ecs v1.41.11/go.mod h1:ixRB9qcKi35waDtPb6uw31Eb7Df+MOcjtpWxxPO5XvI= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 h1:Ji0DY1xUsUr3I8cHps0G+XM3WWU16lP6yG8qu1GAZAs= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2/go.mod h1:5CsjAbs3NlGQyZNFACh+zztPDI7fU6eW9QsxjfnuBKg= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.8 h1:Etk3MkNNAXLKkOkrLcacOZhbH+ICPpM05Wueg/4FZGw= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.8/go.mod h1:LwdzRBRLEOcMRhcM31ltkzl8Nw4XpnmBkOksr+LY53A= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.8 h1:gwdGHxiV5f6Of48JJIZVD7sx45kT1l9kYdoUH5oQTZM= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.8/go.mod h1:C9Glc6N50uIJqPPeL6N3spW/wzGyeQsQmecnKS7DTR4= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.6 h1:T9S8fTr0gppdTU6rjrSBl9VFiabxUw41dqzUSozuQP8= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.6/go.mod h1:mQUaFeeWztcGGBaOxSykT9H/qF+FGw3sCGERh3APsRc= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.11 h1:4vt9Sspk59EZyHCAEMaktHKiq0C09noRTQorXD/qV+s= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.11/go.mod h1:5jHR79Tv+Ccq6rwYh+W7Nptmw++WiFafMfR42XhwNl8= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.11 h1:o4T+fKxA3gTMcluBNZZXE9DNaMkJuUL1O3mffCUjoJo= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.11/go.mod h1:84oZdJ+VjuJKs9v1UTC9NaodRZRseOXCTgku+vQJWR8= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.9 h1:TE2i0A9ErH1YfRSvXfCr2SQwfnqsoJT9nPQ9kj0lkxM= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.9/go.mod h1:9TzXX3MehQNGPwCZ3ka4CpwQsoAMWSF48/b+De9rfVM= github.com/aws/aws-sdk-go-v2/service/rds v1.78.2 h1:xrRLjWcGzeayJT66aP9qnMrn1iKXYaK/+efukoitIXs= github.com/aws/aws-sdk-go-v2/service/rds v1.78.2/go.mod h1:RJaz7FA+m7alWIPQmS6biVBJWY8j6lZ3wqZOf4BtGlg= -github.com/aws/aws-sdk-go-v2/service/s3 v1.54.1 h1:q8hQJhndXQXnCnd4nG608lfhapDvylff9CCQyWX0tHQ= -github.com/aws/aws-sdk-go-v2/service/s3 v1.54.1/go.mod h1:4QIYvQFYGX6Q2qhLW6KeJO0iXQUFJ/WLBL0pSdazHwA= +github.com/aws/aws-sdk-go-v2/service/s3 v1.55.1 h1:UAxBuh0/8sFJk1qOkvOKewP5sWeWaTPDknbQz0ZkDm0= +github.com/aws/aws-sdk-go-v2/service/s3 v1.55.1/go.mod h1:hWjsYGjVuqCgfoveVcVFPXIWgz0aByzwaxKlN1StKcM= github.com/aws/aws-sdk-go-v2/service/ses v1.22.7 h1:9Ytj+pcI/hOjX4m8bpjkbL05XB6GjrHqGuMxFh/jRuA= github.com/aws/aws-sdk-go-v2/service/ses v1.22.7/go.mod h1:sn88fSJSI5LdRbjilmxp2TYs12A6619qj0z1D0fcbuE= github.com/aws/aws-sdk-go-v2/service/ssm v1.50.2 h1:NgeX1fhHrhMqVgF9tydI7WIFDsqReuodPk9bgtQBHoM= @@ -157,8 +157,8 @@ github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7z github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= -github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= +github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk= github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= @@ -201,8 +201,8 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.15.4 h1:zMXza4EpOdooxPel5xDqXEdXG5r+WggpvnAKMsalBjs= -github.com/go-playground/validator/v10 v10.15.4/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-playground/validator/v10 v10.21.0 h1:4fZA11ovvtkdgaeev9RGWPgc1uj3H8W+rNYyH/ySBb0= +github.com/go-playground/validator/v10 v10.21.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= @@ -420,8 +420,8 @@ github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= -github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/lestrrat-go/backoff/v2 v2.0.8 h1:oNb5E5isby2kiro9AgdHLv5N5tint1AnDVVf2E2un5A= github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y= github.com/lestrrat-go/blackmagic v1.0.0/go.mod h1:TNgH//0vYSs8VXDCfkZLgIrVTTXQELZffUV0tz3MtdQ= @@ -619,7 +619,6 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= diff --git a/migrations/app/migrations_manifest.txt b/migrations/app/migrations_manifest.txt index 5f0e618a3f0..44f70216690 100644 --- a/migrations/app/migrations_manifest.txt +++ b/migrations/app/migrations_manifest.txt @@ -928,6 +928,7 @@ 20240502183613_add_support_for_standalone_payment_cap.up.sql 20240503123556_add_diversion_reason_to_mto_shipments.up.sql 20240503181242_add_origin_dest_sit_auth_end_date_to_mto_shipments_table.up.sql +20240506214039_add_submitted_columns_to_ppm_document_tables.up.sql 20240507133524_add_locked_moves_column_to_moves_table.up.sql 20240507155817_add_moving_expense_weight_stored.up.sql 20240507192232_add_emplid_col_to_service_members_table.up.sql @@ -940,4 +941,14 @@ 20240516230021_19686_add_third_address_shipments.up.sql 20240521160335_backfill_LOA_FY_TX.up.sql 20240521184834_add_standalone_field_to_service_items.up.sql +20240522124339_add_csr_to_roles.up.sql +20240524214247_add_sit_location_moving_expenses.up.sql +20240530020648_adding_standalone_crate_service_param.up.sql +20240530084720_rename_qae_csr_to_just_qae.up.sql +20240531050324_adding_standalone_crate_cap.up.sql +20240531152430_migrate_data_to_new_ppm_statuses.up.sql +20240531152526_remove_ppm_statuses_no_longer_used.up.sql 20240531153321_update_tio_role_name.up.sql +20240531154303_add_more_submitted_columns_to_ppm_document_tables.up.sql +20240603040207_add_submitted_cols_to_moving_expenses.up.sql +20240606195706_adding_uncapped_request_total.up.sql diff --git a/migrations/app/schema/20240506214039_add_submitted_columns_to_ppm_document_tables.up.sql b/migrations/app/schema/20240506214039_add_submitted_columns_to_ppm_document_tables.up.sql new file mode 100644 index 00000000000..619f1835d9c --- /dev/null +++ b/migrations/app/schema/20240506214039_add_submitted_columns_to_ppm_document_tables.up.sql @@ -0,0 +1,19 @@ +ALTER TABLE weight_tickets + ADD COLUMN IF NOT EXISTS submitted_empty_weight INT4 DEFAULT NULL, + ADD COLUMN IF NOT EXISTS submitted_full_weight INT4 DEFAULT NULL; + +COMMENT ON COLUMN weight_tickets.submitted_empty_weight IS 'Stores the customer submitted empty_weight.'; +COMMENT ON COLUMN weight_tickets.submitted_full_weight IS 'Stores the customer submitted full_weight.'; + +ALTER TABLE progear_weight_tickets ADD COLUMN IF NOT EXISTS submitted_weight INT4 DEFAULT NULL; + +COMMENT ON COLUMN progear_weight_tickets.submitted_weight IS 'Stores the customer submitted weight.'; + +ALTER TABLE moving_expenses + ADD COLUMN IF NOT EXISTS submitted_amount INT4 DEFAULT NULL, + ADD COLUMN IF NOT EXISTS submitted_sit_start_date DATE DEFAULT NULL, + ADD COLUMN IF NOT EXISTS submitted_sit_end_date DATE DEFAULT NULL; + +COMMENT ON COLUMN moving_expenses.submitted_amount IS 'Stores the customer submitted amount.'; +COMMENT ON COLUMN moving_expenses.submitted_sit_start_date IS 'Stores the customer submitted sit_start_date.'; +COMMENT ON COLUMN moving_expenses.submitted_sit_end_date IS 'Stores the customer submitted sit_end_date.'; diff --git a/migrations/app/schema/20240522124339_add_csr_to_roles.up.sql b/migrations/app/schema/20240522124339_add_csr_to_roles.up.sql new file mode 100644 index 00000000000..4b44df1def7 --- /dev/null +++ b/migrations/app/schema/20240522124339_add_csr_to_roles.up.sql @@ -0,0 +1,9 @@ +-- Insert CSR as a separate role as part of the feature to split QAE/CSR into two separate roles +INSERT INTO roles (id, role_type, created_at, updated_at, role_name) +VALUES ( + '72432922-BF2E-45DE-8837-1A458F5D1011', + 'customer_service_representative', + now(), + now(), + 'Customer Service Representative' + ); \ No newline at end of file diff --git a/migrations/app/schema/20240524214247_add_sit_location_moving_expenses.up.sql b/migrations/app/schema/20240524214247_add_sit_location_moving_expenses.up.sql new file mode 100644 index 00000000000..0e1ab04d6d6 --- /dev/null +++ b/migrations/app/schema/20240524214247_add_sit_location_moving_expenses.up.sql @@ -0,0 +1,2 @@ +ALTER TABLE moving_expenses ADD COLUMN IF NOT EXISTS sit_location sit_location_type NULL; +COMMENT ON COLUMN moving_expenses.sit_location IS 'The location where PPM SIT was stored'; \ No newline at end of file diff --git a/migrations/app/schema/20240530020648_adding_standalone_crate_service_param.up.sql b/migrations/app/schema/20240530020648_adding_standalone_crate_service_param.up.sql new file mode 100644 index 00000000000..22024d15aad --- /dev/null +++ b/migrations/app/schema/20240530020648_adding_standalone_crate_service_param.up.sql @@ -0,0 +1,11 @@ +INSERT INTO service_item_param_keys +(id,key,description,type,origin,created_at,updated_at) +VALUES +('4313f804-f6c7-496a-88a0-089d6c588b75','StandaloneCrate', 'Boolean representing standalone or not', 'BOOLEAN', 'PRIME', now(), now()), +('ca1d6588-880e-45b6-9761-aa2ce914e2f6','StandaloneCrateCap', 'Standalone Cap value used for this service', 'INTEGER', 'PRIME', now(), now()); + +INSERT INTO service_params +(id,service_id,service_item_param_key_id,created_at,updated_at,is_optional) +VALUES +('3a051dbf-f8b1-4c09-9ed8-74e155c69a5d',(SELECT id FROM re_services WHERE code='DCRT'),(SELECT id FROM service_item_param_keys where key='StandaloneCrate'), now(), now(), 'true'), +('b1de3b51-9cd8-43ab-b186-ca4c7796be03',(SELECT id FROM re_services WHERE code='DCRT'),(SELECT id FROM service_item_param_keys where key='StandaloneCrateCap'), now(), now(), 'true'); diff --git a/migrations/app/schema/20240530084720_rename_qae_csr_to_just_qae.up.sql b/migrations/app/schema/20240530084720_rename_qae_csr_to_just_qae.up.sql new file mode 100644 index 00000000000..3e8c318647e --- /dev/null +++ b/migrations/app/schema/20240530084720_rename_qae_csr_to_just_qae.up.sql @@ -0,0 +1,6 @@ +-- Rename QAE/CSR to just QAE per E-05337 +UPDATE roles +SET role_name = 'Quality Assurance Evaluator', + role_type = 'qae', + updated_at = now() +WHERE id = 'a2af3cc0-d0cd-4a29-8092-70ad45723090'; \ No newline at end of file diff --git a/migrations/app/schema/20240531050324_adding_standalone_crate_cap.up.sql b/migrations/app/schema/20240531050324_adding_standalone_crate_cap.up.sql new file mode 100644 index 00000000000..0d2c3de87d9 --- /dev/null +++ b/migrations/app/schema/20240531050324_adding_standalone_crate_cap.up.sql @@ -0,0 +1,4 @@ +INSERT into application_parameters + (id, parameter_name, parameter_value) +VALUES + ('61a6c498-42d3-4b49-b368-b6165cd1ce18', 'standaloneCrateCap', '100000'); \ No newline at end of file diff --git a/migrations/app/schema/20240531152430_migrate_data_to_new_ppm_statuses.up.sql b/migrations/app/schema/20240531152430_migrate_data_to_new_ppm_statuses.up.sql new file mode 100644 index 00000000000..041e6913ade --- /dev/null +++ b/migrations/app/schema/20240531152430_migrate_data_to_new_ppm_statuses.up.sql @@ -0,0 +1,17 @@ +--- rename existing enum +ALTER TYPE ppm_shipment_status RENAME TO ppm_shipment_status_temp; + +-- create a new enum with both old and new statuses +-- why? because both old and new statuses must exist in the enum to do the update setting old to new +CREATE TYPE ppm_shipment_status AS ENUM('DRAFT', 'SUBMITTED', 'WAITING_ON_CUSTOMER', 'NEEDS_ADVANCE_APPROVAL', 'NEEDS_PAYMENT_APPROVAL', 'PAYMENT_APPROVED', 'NEEDS_CLOSEOUT', 'CLOSEOUT_COMPLETE'); + +-- alter the ppm shipments status column to use the new enum +ALTER TABLE ppm_shipments ALTER COLUMN status TYPE ppm_shipment_status USING status::text::ppm_shipment_status; + +-- get rid of the temp type +DROP TYPE ppm_shipment_status_temp; + +-- Remove references to the old value from the ppm_shipments table (there probably aren't any, but this is for safety) +UPDATE ppm_shipments set status = 'NEEDS_CLOSEOUT' WHERE status = 'NEEDS_PAYMENT_APPROVAL'; +UPDATE ppm_shipments set status = 'CLOSEOUT_COMPLETE' WHERE status = 'PAYMENT_APPROVED'; + diff --git a/migrations/app/schema/20240531152526_remove_ppm_statuses_no_longer_used.up.sql b/migrations/app/schema/20240531152526_remove_ppm_statuses_no_longer_used.up.sql new file mode 100644 index 00000000000..355c4932c99 --- /dev/null +++ b/migrations/app/schema/20240531152526_remove_ppm_statuses_no_longer_used.up.sql @@ -0,0 +1,12 @@ +--- rename existing enum +ALTER TYPE ppm_shipment_status RENAME TO ppm_shipment_status_temp; + +-- create a new enum with both old and new statuses +-- why? because both old and new statuses must exist in the enum to do the update setting old to new +CREATE TYPE ppm_shipment_status AS ENUM('DRAFT', 'SUBMITTED', 'WAITING_ON_CUSTOMER', 'NEEDS_ADVANCE_APPROVAL', 'NEEDS_CLOSEOUT', 'CLOSEOUT_COMPLETE'); + +-- alter the ppm shipments status column to use the new enum +ALTER TABLE ppm_shipments ALTER COLUMN status TYPE ppm_shipment_status USING status::text::ppm_shipment_status; + +-- get rid of the temp type +DROP TYPE ppm_shipment_status_temp; diff --git a/migrations/app/schema/20240531154303_add_more_submitted_columns_to_ppm_document_tables.up.sql b/migrations/app/schema/20240531154303_add_more_submitted_columns_to_ppm_document_tables.up.sql new file mode 100644 index 00000000000..f807821fb70 --- /dev/null +++ b/migrations/app/schema/20240531154303_add_more_submitted_columns_to_ppm_document_tables.up.sql @@ -0,0 +1,13 @@ +ALTER TABLE weight_tickets + ADD COLUMN IF NOT EXISTS submitted_owns_trailer boolean DEFAULT NULL, + ADD COLUMN IF NOT EXISTS submitted_trailer_meets_criteria boolean DEFAULT NULL; + +COMMENT ON COLUMN weight_tickets.submitted_owns_trailer IS 'Stores the customer submitted owns_trailer.'; +COMMENT ON COLUMN weight_tickets.submitted_trailer_meets_criteria IS 'Stores the customer submitted trailer_meets_criteria.'; + +ALTER TABLE progear_weight_tickets + ADD COLUMN IF NOT EXISTS submitted_belongs_to_self boolean DEFAULT NULL, + ADD COLUMN IF NOT EXISTS submitted_has_weight_tickets boolean DEFAULT NULL; + +COMMENT ON COLUMN progear_weight_tickets.submitted_belongs_to_self IS 'Stores the customer belongs_to_self.'; +COMMENT ON COLUMN progear_weight_tickets.submitted_has_weight_tickets IS 'Stores the customer submitted has_weight_tickets.'; diff --git a/migrations/app/schema/20240603040207_add_submitted_cols_to_moving_expenses.up.sql b/migrations/app/schema/20240603040207_add_submitted_cols_to_moving_expenses.up.sql new file mode 100644 index 00000000000..89550db0f9e --- /dev/null +++ b/migrations/app/schema/20240603040207_add_submitted_cols_to_moving_expenses.up.sql @@ -0,0 +1,6 @@ +ALTER TABLE moving_expenses + ADD COLUMN IF NOT EXISTS submitted_description varchar DEFAULT NULL, + ADD COLUMN IF NOT EXISTS submitted_moving_expense_type moving_expense_type DEFAULT NULL; + +COMMENT ON COLUMN moving_expenses.submitted_description IS 'Stores the customer submitted description'; +COMMENT ON COLUMN moving_expenses.submitted_moving_expense_type IS 'Stores the customer submitted moving_expense_type.'; diff --git a/migrations/app/schema/20240606195706_adding_uncapped_request_total.up.sql b/migrations/app/schema/20240606195706_adding_uncapped_request_total.up.sql new file mode 100644 index 00000000000..c7ae330e18e --- /dev/null +++ b/migrations/app/schema/20240606195706_adding_uncapped_request_total.up.sql @@ -0,0 +1,9 @@ +INSERT INTO service_item_param_keys +(id,key,description,type,origin,created_at,updated_at) +VALUES +('71b27fef-a328-40ab-9e21-a22000e9a4c2','UncappedRequestTotal', 'Total request before cap', 'INTEGER', 'PRICER', now(), now()); + +INSERT INTO service_params +(id,service_id,service_item_param_key_id,created_at,updated_at,is_optional) +VALUES +('e246ad86-1ad5-43c8-ab22-e0c6dc941200',(SELECT id FROM re_services WHERE code='DCRT'),(SELECT id FROM service_item_param_keys where key='UncappedRequestTotal'), now(), now(), 'true'); \ No newline at end of file diff --git a/pkg/assets/paperwork/formtemplates/SSWPDFTemplate.pdf b/pkg/assets/paperwork/formtemplates/SSWPDFTemplate.pdf index 134d51b0be1..26ddb380d8d 100644 Binary files a/pkg/assets/paperwork/formtemplates/SSWPDFTemplate.pdf and b/pkg/assets/paperwork/formtemplates/SSWPDFTemplate.pdf differ diff --git a/pkg/factory/ppm_shipment_factory.go b/pkg/factory/ppm_shipment_factory.go index eea4c81d089..e54e13e54e5 100644 --- a/pkg/factory/ppm_shipment_factory.go +++ b/pkg/factory/ppm_shipment_factory.go @@ -550,13 +550,13 @@ func BuildPPMShipmentReadyForFinalCustomerCloseOutWithAllDocTypes(db *pop.Connec return ppmShipment } -// BuildPPMShipmentThatNeedsPaymentApproval creates a PPMShipment that +// BuildPPMShipmentThatNeedsCloseout creates a PPMShipment that // is waiting for a counselor to review after a customer has submitted // all the necessary documents. // // This function needs to accept customizations, but that somewhat // complicates the private functions above -func BuildPPMShipmentThatNeedsPaymentApproval(db *pop.Connection, userUploader *uploader.UserUploader, customs []Customization) models.PPMShipment { +func BuildPPMShipmentThatNeedsCloseout(db *pop.Connection, userUploader *uploader.UserUploader, customs []Customization) models.PPMShipment { // It's easier to use some of the data from other downstream // functions if we have them go first and then make our changes on // top of those changes. @@ -580,7 +580,7 @@ func BuildPPMShipmentThatNeedsPaymentApproval(db *pop.Connection, userUploader * ppmShipment.SignedCertification = &signedCert - ppmShipment.Status = models.PPMShipmentStatusNeedsPaymentApproval + ppmShipment.Status = models.PPMShipmentStatusNeedsCloseout if ppmShipment.SubmittedAt == nil { ppmShipment.SubmittedAt = models.TimePointer(time.Now()) } @@ -598,7 +598,7 @@ func BuildPPMShipmentThatNeedsPaymentApproval(db *pop.Connection, userUploader * return ppmShipment } -// BuildPPMShipmentThatNeedsPaymentApprovalWithAllDocTypes creates a +// BuildPPMShipmentThatNeedsCloseoutWithAllDocTypes creates a // PPMShipment that contains one of each type of customer document // (weight ticket, pro-gear weight ticket, and a moving expense) that // is waiting for a counselor to review after a customer has submitted @@ -606,11 +606,11 @@ func BuildPPMShipmentThatNeedsPaymentApproval(db *pop.Connection, userUploader * // // This function does not accept customizations to reduce the // complexity of supporting different variations for tests -func BuildPPMShipmentThatNeedsPaymentApprovalWithAllDocTypes(db *pop.Connection, userUploader *uploader.UserUploader) models.PPMShipment { +func BuildPPMShipmentThatNeedsCloseoutWithAllDocTypes(db *pop.Connection, userUploader *uploader.UserUploader) models.PPMShipment { // It's easier to use some of the data from other downstream // functions if we have them go first and then make our changes on // top of those changes. - ppmShipment := BuildPPMShipmentThatNeedsPaymentApproval(db, userUploader, nil) + ppmShipment := BuildPPMShipmentThatNeedsCloseout(db, userUploader, nil) AddProgearWeightTicketToPPMShipment(db, &ppmShipment, userUploader, nil) AddMovingExpenseToPPMShipment(db, &ppmShipment, userUploader, nil) @@ -634,9 +634,9 @@ func BuildPPMShipmentWithApprovedDocumentsMissingPaymentPacket(db *pop.Connectio // It's easier to use some of the data from other downstream // functions if we have them go first and then make our changes on // top of those changes. - ppmShipment := BuildPPMShipmentThatNeedsPaymentApproval(db, userUploader, customs) + ppmShipment := BuildPPMShipmentThatNeedsCloseout(db, userUploader, customs) - ppmShipment.Status = models.PPMShipmentStatusPaymentApproved + ppmShipment.Status = models.PPMShipmentStatusCloseoutComplete ppmShipment.ReviewedAt = models.TimePointer(time.Now()) approvedStatus := models.PPMDocumentStatusApproved @@ -778,7 +778,7 @@ func BuildPPMShipmentThatNeedsToBeResubmitted(db *pop.Connection, userUploader * // It's easier to use some of the data from other downstream // functions if we have them go first and then make our changes on // top of those changes. - ppmShipment := BuildPPMShipmentThatNeedsPaymentApproval(db, userUploader, nil) + ppmShipment := BuildPPMShipmentThatNeedsCloseout(db, userUploader, nil) // Document that got rejected. This would normally already exist // and would just need to be updated to change the status, but for diff --git a/pkg/factory/ppm_shipment_factory_test.go b/pkg/factory/ppm_shipment_factory_test.go index 0dd41e25ed7..0dff96de000 100644 --- a/pkg/factory/ppm_shipment_factory_test.go +++ b/pkg/factory/ppm_shipment_factory_test.go @@ -306,12 +306,12 @@ func (suite *FactorySuite) TestBuildPPMShipment() { }) suite.Run("PPM Shipment that needs approval with all doc types", func() { - // Under test: BuildPPMShipmentThatNeedsPaymentApprovalWithAllDocTypes + // Under test: BuildPPMShipmentThatNeedsCloseoutWithAllDocTypes // Set up: build without custom user uploader // Expected outcome: New PPMShipment should be created with // Weight Ticket, Progear Weight Ticket, and Moving Expense - ppmShipment := BuildPPMShipmentThatNeedsPaymentApprovalWithAllDocTypes(suite.DB(), nil) + ppmShipment := BuildPPMShipmentThatNeedsCloseoutWithAllDocTypes(suite.DB(), nil) suite.NotNil(ppmShipment.ActualPickupPostalCode) suite.Equal(ppmShipment.PickupPostalCode, *ppmShipment.ActualPickupPostalCode) @@ -320,7 +320,7 @@ func (suite *FactorySuite) TestBuildPPMShipment() { *ppmShipment.ActualDestinationPostalCode) suite.NotNil(ppmShipment.AOAPacket) suite.NotNil(ppmShipment.AOAPacketID) - suite.Equal(models.PPMShipmentStatusNeedsPaymentApproval, ppmShipment.Status) + suite.Equal(models.PPMShipmentStatusNeedsCloseout, ppmShipment.Status) suite.NotEmpty(ppmShipment.WeightTickets) suite.Equal(1, len(ppmShipment.WeightTickets)) @@ -339,7 +339,7 @@ func (suite *FactorySuite) TestBuildPPMShipment() { }) suite.Run("PPM Shipment that is missing payment packet", func() { - // Under test: BuildPPMShipmentThatNeedsPaymentApprovalWithAllDocTypes + // Under test: BuildPPMShipmentThatNeedsCloseoutWithAllDocTypes // Set up: build without custom user uploader // Expected outcome: New PPMShipment should be created with // Weight Ticket, Progear Weight Ticket, and Moving Expense @@ -353,7 +353,7 @@ func (suite *FactorySuite) TestBuildPPMShipment() { *ppmShipment.ActualDestinationPostalCode) suite.NotNil(ppmShipment.AOAPacket) suite.NotNil(ppmShipment.AOAPacketID) - suite.Equal(models.PPMShipmentStatusPaymentApproved, ppmShipment.Status) + suite.Equal(models.PPMShipmentStatusCloseoutComplete, ppmShipment.Status) suite.NotEmpty(ppmShipment.WeightTickets) suite.Equal(1, len(ppmShipment.WeightTickets)) diff --git a/pkg/factory/role_factory.go b/pkg/factory/role_factory.go index 60483c15ef5..d16bdcaa9f0 100644 --- a/pkg/factory/role_factory.go +++ b/pkg/factory/role_factory.go @@ -97,12 +97,23 @@ func GetTraitTOORole() []Customization { } } -func GetTraitQaeCsrRole() []Customization { +func GetTraitQaeRole() []Customization { return []Customization{ { Model: roles.Role{ - RoleType: roles.RoleTypeQaeCsr, - RoleName: "Quality Assurance and Customer Service", + RoleType: roles.RoleTypeQae, + RoleName: "Quality Assurance Evaluator", + }, + }, + } +} + +func GetTraitCustomerServiceRepresentativeRole() []Customization { + return []Customization{ + { + Model: roles.Role{ + RoleType: roles.RoleTypeCustomerServiceRepresentative, + RoleName: "Customer Service Representative", }, }, } diff --git a/pkg/factory/role_factory_test.go b/pkg/factory/role_factory_test.go index 4d7bb97a35c..f82470d2488 100644 --- a/pkg/factory/role_factory_test.go +++ b/pkg/factory/role_factory_test.go @@ -120,17 +120,17 @@ func (suite *FactorySuite) TestBuildRoleTraits() { suite.Equal(roles.RoleTypeTOO, role.RoleType) }) - suite.Run("Successful creation of role with QaeCsr trait", func() { + suite.Run("Successful creation of role with Qae trait", func() { // Under test: BuildRole - // Set up: Create a Role with a trait (GetTraitQaeCsrRole) + // Set up: Create a Role with a trait (GetTraitQaeRole) // Expected outcome:Role should be created with TIO RoleType and RoleName role := BuildRole(suite.DB(), nil, []Trait{ - GetTraitQaeCsrRole, + GetTraitQaeRole, }) - suite.Equal(roles.RoleName("Quality Assurance and Customer Service"), role.RoleName) - suite.Equal(roles.RoleTypeQaeCsr, role.RoleType) + suite.Equal(roles.RoleName("Quality Assurance Evaluator"), role.RoleName) + suite.Equal(roles.RoleTypeQae, role.RoleType) }) suite.Run("Successful creation of role with Contracting Officer trait", func() { diff --git a/pkg/gen/ghcapi/configure_mymove.go b/pkg/gen/ghcapi/configure_mymove.go index 86b0fd7c50e..8085352f929 100644 --- a/pkg/gen/ghcapi/configure_mymove.go +++ b/pkg/gen/ghcapi/configure_mymove.go @@ -11,6 +11,7 @@ import ( "github.com/go-openapi/runtime/middleware" "github.com/transcom/mymove/pkg/gen/ghcapi/ghcoperations" + "github.com/transcom/mymove/pkg/gen/ghcapi/ghcoperations/application_parameters" "github.com/transcom/mymove/pkg/gen/ghcapi/ghcoperations/customer" "github.com/transcom/mymove/pkg/gen/ghcapi/ghcoperations/customer_support_remarks" "github.com/transcom/mymove/pkg/gen/ghcapi/ghcoperations/evaluation_reports" @@ -258,6 +259,11 @@ func configureAPI(api *ghcoperations.MymoveAPI) http.Handler { return middleware.NotImplemented("operation pws_violations.GetPWSViolations has not yet been implemented") }) } + if api.ApplicationParametersGetParamHandler == nil { + api.ApplicationParametersGetParamHandler = application_parameters.GetParamHandlerFunc(func(params application_parameters.GetParamParams) middleware.Responder { + return middleware.NotImplemented("operation application_parameters.GetParam has not yet been implemented") + }) + } if api.PaymentRequestsGetPaymentRequestHandler == nil { api.PaymentRequestsGetPaymentRequestHandler = payment_requests.GetPaymentRequestHandlerFunc(func(params payment_requests.GetPaymentRequestParams) middleware.Responder { return middleware.NotImplemented("operation payment_requests.GetPaymentRequest has not yet been implemented") diff --git a/pkg/gen/ghcapi/embedded_spec.go b/pkg/gen/ghcapi/embedded_spec.go index 1a3a39a9897..e706d3737a1 100644 --- a/pkg/gen/ghcapi/embedded_spec.go +++ b/pkg/gen/ghcapi/embedded_spec.go @@ -36,6 +36,43 @@ func init() { }, "basePath": "/ghc/v1", "paths": { + "/application_parameters/{parameterName}": { + "get": { + "description": "Searches for an application parameter by name, returns nil if not found", + "tags": [ + "application_parameters" + ], + "summary": "Searches for an application parameter by name, returns nil if not found", + "operationId": "getParam", + "parameters": [ + { + "type": "string", + "format": "string", + "description": "Parameter Name", + "name": "parameterName", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Application Parameters", + "schema": { + "$ref": "#/definitions/ApplicationParameters" + } + }, + "400": { + "description": "invalid request" + }, + "401": { + "description": "request requires user authentication" + }, + "500": { + "description": "server error" + } + } + } + }, "/counseling/orders/{orderID}": { "patch": { "description": "All fields sent in this request will be set on the order referenced", @@ -5361,6 +5398,26 @@ func init() { }, "x-nullable": true }, + "ApplicationParameters": { + "type": "object", + "properties": { + "parameterName": { + "type": "string", + "format": "string", + "x-nullable": true + }, + "parameterValue": { + "type": "string", + "format": "string", + "x-nullable": true + }, + "validationCode": { + "type": "string", + "format": "string", + "x-nullable": true + } + } + }, "ApproveSITExtension": { "required": [ "approvedDays" @@ -6125,7 +6182,8 @@ func init() { "$ref": "#/definitions/BackupContact" }, "cacValidated": { - "type": "boolean" + "type": "boolean", + "x-nullable": true }, "current_address": { "$ref": "#/definitions/Address" @@ -6995,6 +7053,11 @@ func init() { "eTag": { "type": "string" }, + "estimatedPrice": { + "type": "integer", + "format": "cents", + "x-nullable": true + }, "estimatedWeight": { "description": "estimated weight of the shuttle service item provided by the prime", "type": "integer", @@ -7103,6 +7166,10 @@ func init() { "format": "date", "x-nullable": true }, + "standaloneCrate": { + "type": "boolean", + "x-nullable": true + }, "status": { "$ref": "#/definitions/MTOServiceItemStatus" }, @@ -8124,6 +8191,19 @@ func init() { "x-omitempty": false, "example": "2018-05-26" }, + "sitLocation": { + "allOf": [ + { + "$ref": "#/definitions/SITLocationType" + }, + { + "x-nullable": true + }, + { + "x-omitempty": false + } + ] + }, "sitStartDate": { "description": "The date the shipment entered storage, applicable for the ` + "`" + `STORAGE` + "`" + ` movingExpenseType only", "type": "string", @@ -9111,49 +9191,49 @@ func init() { "x-omitempty": false }, "tertiaryDestinationAddress": { - "allOf": [ - { - "$ref": "#/definitions/Address" - }, - { - "x-nullable": true - }, - { - "x-omitempty": false - } - ] - }, - "tertiaryDestinationPostalCode": { - "type": "string", - "format": "An optional secondary pickup location near the origin where additional goods exist.", - "title": "ZIP", - "pattern": "^(\\d{5})$", - "x-nullable": true, - "x-omitempty": false, - "example": "90210" - }, - "tertiaryPickupAddress": { - "allOf": [ - { - "$ref": "#/definitions/Address" - }, - { - "x-nullable": true - }, - { - "x-omitempty": false - } - ] - }, - "tertiaryPickupPostalCode": { - "type": "string", - "format": "An optional secondary pickup location near the origin where additional goods exist.", - "title": "ZIP", - "pattern": "^(\\d{5})$", - "x-nullable": true, - "x-omitempty": false, - "example": "90210" - }, + "allOf": [ + { + "$ref": "#/definitions/Address" + }, + { + "x-nullable": true + }, + { + "x-omitempty": false + } + ] + }, + "tertiaryDestinationPostalCode": { + "type": "string", + "format": "An optional secondary pickup location near the origin where additional goods exist.", + "title": "ZIP", + "pattern": "^(\\d{5})$", + "x-nullable": true, + "x-omitempty": false, + "example": "90210" + }, + "tertiaryPickupAddress": { + "allOf": [ + { + "$ref": "#/definitions/Address" + }, + { + "x-nullable": true + }, + { + "x-omitempty": false + } + ] + }, + "tertiaryPickupPostalCode": { + "type": "string", + "format": "An optional secondary pickup location near the origin where additional goods exist.", + "title": "ZIP", + "pattern": "^(\\d{5})$", + "x-nullable": true, + "x-omitempty": false, + "example": "90210" + }, "updatedAt": { "description": "Timestamp of when a property of this object was last updated (UTC)", "type": "string", @@ -9171,15 +9251,15 @@ func init() { "x-nullable": true }, "PPMShipmentStatus": { - "description": "Status of the PPM Shipment:\n * **DRAFT**: The customer has created the PPM shipment but has not yet submitted their move for counseling.\n * **SUBMITTED**: The shipment belongs to a move that has been submitted by the customer or has been created by a Service Counselor or Prime Contractor for a submitted move.\n * **WAITING_ON_CUSTOMER**: The PPM shipment has been approved and the customer may now provide their actual move closeout information and documentation required to get paid.\n * **NEEDS_ADVANCE_APPROVAL**: The shipment was counseled by the Prime Contractor and approved but an advance was requested so will need further financial approval from the government.\n * **NEEDS_PAYMENT_APPROVAL**: The customer has provided their closeout weight tickets, receipts, and expenses and certified it for the Service Counselor to approve, exclude or reject.\n * **PAYMENT_APPROVED**: The Service Counselor has reviewed all of the customer's PPM closeout documentation and authorizes the customer can download and submit their finalized SSW packet.\n", + "description": "Status of the PPM Shipment:\n * **DRAFT**: The customer has created the PPM shipment but has not yet submitted their move for counseling.\n * **SUBMITTED**: The shipment belongs to a move that has been submitted by the customer or has been created by a Service Counselor or Prime Contractor for a submitted move.\n * **WAITING_ON_CUSTOMER**: The PPM shipment has been approved and the customer may now provide their actual move closeout information and documentation required to get paid.\n * **NEEDS_ADVANCE_APPROVAL**: The shipment was counseled by the Prime Contractor and approved but an advance was requested so will need further financial approval from the government.\n * **NEEDS_CLOSEOUT**: The customer has provided their closeout weight tickets, receipts, and expenses and certified it for the Service Counselor to approve, exclude or reject.\n * **CLOSEOUT_COMPLETE**: The Service Counselor has reviewed all of the customer's PPM closeout documentation and authorizes the customer can download and submit their finalized SSW packet.\n", "type": "string", "enum": [ "DRAFT", "SUBMITTED", "WAITING_ON_CUSTOMER", "NEEDS_ADVANCE_APPROVAL", - "NEEDS_PAYMENT_APPROVAL", - "PAYMENT_APPROVED" + "NEEDS_CLOSEOUT", + "CLOSEOUT_COMPLETE" ], "readOnly": true }, @@ -10356,7 +10436,10 @@ func init() { "ZipSITDestHHGFinalAddress", "ZipSITDestHHGOriginalAddress", "ZipSITOriginHHGActualAddress", - "ZipSITOriginHHGOriginalAddress" + "ZipSITOriginHHGOriginalAddress", + "StandaloneCrate", + "StandaloneCrateCap", + "UncappedRequestTotal" ] }, "ServiceItemParamOrigin": { @@ -10938,6 +11021,16 @@ func init() { "type": "string", "format": "date" }, + "sitLocation": { + "allOf": [ + { + "$ref": "#/definitions/SITLocationType" + }, + { + "x-nullable": true + } + ] + }, "sitStartDate": { "description": "The date the shipment entered storage, applicable for the ` + "`" + `STORAGE` + "`" + ` movingExpenseType only", "type": "string", @@ -11798,6 +11891,43 @@ func init() { }, "basePath": "/ghc/v1", "paths": { + "/application_parameters/{parameterName}": { + "get": { + "description": "Searches for an application parameter by name, returns nil if not found", + "tags": [ + "application_parameters" + ], + "summary": "Searches for an application parameter by name, returns nil if not found", + "operationId": "getParam", + "parameters": [ + { + "type": "string", + "format": "string", + "description": "Parameter Name", + "name": "parameterName", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Application Parameters", + "schema": { + "$ref": "#/definitions/ApplicationParameters" + } + }, + "400": { + "description": "invalid request" + }, + "401": { + "description": "request requires user authentication" + }, + "500": { + "description": "server error" + } + } + } + }, "/counseling/orders/{orderID}": { "patch": { "description": "All fields sent in this request will be set on the order referenced", @@ -18453,6 +18583,26 @@ func init() { }, "x-nullable": true }, + "ApplicationParameters": { + "type": "object", + "properties": { + "parameterName": { + "type": "string", + "format": "string", + "x-nullable": true + }, + "parameterValue": { + "type": "string", + "format": "string", + "x-nullable": true + }, + "validationCode": { + "type": "string", + "format": "string", + "x-nullable": true + } + } + }, "ApproveSITExtension": { "required": [ "approvedDays" @@ -19221,7 +19371,8 @@ func init() { "$ref": "#/definitions/BackupContact" }, "cacValidated": { - "type": "boolean" + "type": "boolean", + "x-nullable": true }, "current_address": { "$ref": "#/definitions/Address" @@ -20091,6 +20242,11 @@ func init() { "eTag": { "type": "string" }, + "estimatedPrice": { + "type": "integer", + "format": "cents", + "x-nullable": true + }, "estimatedWeight": { "description": "estimated weight of the shuttle service item provided by the prime", "type": "integer", @@ -20199,6 +20355,10 @@ func init() { "format": "date", "x-nullable": true }, + "standaloneCrate": { + "type": "boolean", + "x-nullable": true + }, "status": { "$ref": "#/definitions/MTOServiceItemStatus" }, @@ -21220,6 +21380,19 @@ func init() { "x-omitempty": false, "example": "2018-05-26" }, + "sitLocation": { + "allOf": [ + { + "$ref": "#/definitions/SITLocationType" + }, + { + "x-nullable": true + }, + { + "x-omitempty": false + } + ] + }, "sitStartDate": { "description": "The date the shipment entered storage, applicable for the ` + "`" + `STORAGE` + "`" + ` movingExpenseType only", "type": "string", @@ -22208,49 +22381,49 @@ func init() { "x-omitempty": false }, "tertiaryDestinationAddress": { - "allOf": [ - { - "$ref": "#/definitions/Address" - }, - { - "x-nullable": true - }, - { - "x-omitempty": false - } - ] - }, - "tertiaryDestinationPostalCode": { - "type": "string", - "format": "An optional secondary pickup location near the origin where additional goods exist.", - "title": "ZIP", - "pattern": "^(\\d{5})$", - "x-nullable": true, - "x-omitempty": false, - "example": "90210" - }, - "tertiaryPickupAddress": { - "allOf": [ - { - "$ref": "#/definitions/Address" - }, - { - "x-nullable": true - }, - { - "x-omitempty": false - } - ] - }, - "tertiaryPickupPostalCode": { - "type": "string", - "format": "An optional secondary pickup location near the origin where additional goods exist.", - "title": "ZIP", - "pattern": "^(\\d{5})$", - "x-nullable": true, - "x-omitempty": false, - "example": "90210" - }, + "allOf": [ + { + "$ref": "#/definitions/Address" + }, + { + "x-nullable": true + }, + { + "x-omitempty": false + } + ] + }, + "tertiaryDestinationPostalCode": { + "type": "string", + "format": "An optional secondary pickup location near the origin where additional goods exist.", + "title": "ZIP", + "pattern": "^(\\d{5})$", + "x-nullable": true, + "x-omitempty": false, + "example": "90210" + }, + "tertiaryPickupAddress": { + "allOf": [ + { + "$ref": "#/definitions/Address" + }, + { + "x-nullable": true + }, + { + "x-omitempty": false + } + ] + }, + "tertiaryPickupPostalCode": { + "type": "string", + "format": "An optional secondary pickup location near the origin where additional goods exist.", + "title": "ZIP", + "pattern": "^(\\d{5})$", + "x-nullable": true, + "x-omitempty": false, + "example": "90210" + }, "updatedAt": { "description": "Timestamp of when a property of this object was last updated (UTC)", "type": "string", @@ -22268,15 +22441,15 @@ func init() { "x-nullable": true }, "PPMShipmentStatus": { - "description": "Status of the PPM Shipment:\n * **DRAFT**: The customer has created the PPM shipment but has not yet submitted their move for counseling.\n * **SUBMITTED**: The shipment belongs to a move that has been submitted by the customer or has been created by a Service Counselor or Prime Contractor for a submitted move.\n * **WAITING_ON_CUSTOMER**: The PPM shipment has been approved and the customer may now provide their actual move closeout information and documentation required to get paid.\n * **NEEDS_ADVANCE_APPROVAL**: The shipment was counseled by the Prime Contractor and approved but an advance was requested so will need further financial approval from the government.\n * **NEEDS_PAYMENT_APPROVAL**: The customer has provided their closeout weight tickets, receipts, and expenses and certified it for the Service Counselor to approve, exclude or reject.\n * **PAYMENT_APPROVED**: The Service Counselor has reviewed all of the customer's PPM closeout documentation and authorizes the customer can download and submit their finalized SSW packet.\n", + "description": "Status of the PPM Shipment:\n * **DRAFT**: The customer has created the PPM shipment but has not yet submitted their move for counseling.\n * **SUBMITTED**: The shipment belongs to a move that has been submitted by the customer or has been created by a Service Counselor or Prime Contractor for a submitted move.\n * **WAITING_ON_CUSTOMER**: The PPM shipment has been approved and the customer may now provide their actual move closeout information and documentation required to get paid.\n * **NEEDS_ADVANCE_APPROVAL**: The shipment was counseled by the Prime Contractor and approved but an advance was requested so will need further financial approval from the government.\n * **NEEDS_CLOSEOUT**: The customer has provided their closeout weight tickets, receipts, and expenses and certified it for the Service Counselor to approve, exclude or reject.\n * **CLOSEOUT_COMPLETE**: The Service Counselor has reviewed all of the customer's PPM closeout documentation and authorizes the customer can download and submit their finalized SSW packet.\n", "type": "string", "enum": [ "DRAFT", "SUBMITTED", "WAITING_ON_CUSTOMER", "NEEDS_ADVANCE_APPROVAL", - "NEEDS_PAYMENT_APPROVAL", - "PAYMENT_APPROVED" + "NEEDS_CLOSEOUT", + "CLOSEOUT_COMPLETE" ], "readOnly": true }, @@ -23504,7 +23677,10 @@ func init() { "ZipSITDestHHGFinalAddress", "ZipSITDestHHGOriginalAddress", "ZipSITOriginHHGActualAddress", - "ZipSITOriginHHGOriginalAddress" + "ZipSITOriginHHGOriginalAddress", + "StandaloneCrate", + "StandaloneCrateCap", + "UncappedRequestTotal" ] }, "ServiceItemParamOrigin": { @@ -24092,6 +24268,16 @@ func init() { "type": "string", "format": "date" }, + "sitLocation": { + "allOf": [ + { + "$ref": "#/definitions/SITLocationType" + }, + { + "x-nullable": true + } + ] + }, "sitStartDate": { "description": "The date the shipment entered storage, applicable for the ` + "`" + `STORAGE` + "`" + ` movingExpenseType only", "type": "string", diff --git a/pkg/gen/ghcapi/ghcoperations/application_parameters/get_param.go b/pkg/gen/ghcapi/ghcoperations/application_parameters/get_param.go new file mode 100644 index 00000000000..209ae670952 --- /dev/null +++ b/pkg/gen/ghcapi/ghcoperations/application_parameters/get_param.go @@ -0,0 +1,58 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package application_parameters + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the generate command + +import ( + "net/http" + + "github.com/go-openapi/runtime/middleware" +) + +// GetParamHandlerFunc turns a function with the right signature into a get param handler +type GetParamHandlerFunc func(GetParamParams) middleware.Responder + +// Handle executing the request and returning a response +func (fn GetParamHandlerFunc) Handle(params GetParamParams) middleware.Responder { + return fn(params) +} + +// GetParamHandler interface for that can handle valid get param params +type GetParamHandler interface { + Handle(GetParamParams) middleware.Responder +} + +// NewGetParam creates a new http.Handler for the get param operation +func NewGetParam(ctx *middleware.Context, handler GetParamHandler) *GetParam { + return &GetParam{Context: ctx, Handler: handler} +} + +/* + GetParam swagger:route GET /application_parameters/{parameterName} application_parameters getParam + +# Searches for an application parameter by name, returns nil if not found + +Searches for an application parameter by name, returns nil if not found +*/ +type GetParam struct { + Context *middleware.Context + Handler GetParamHandler +} + +func (o *GetParam) ServeHTTP(rw http.ResponseWriter, r *http.Request) { + route, rCtx, _ := o.Context.RouteInfo(r) + if rCtx != nil { + *r = *rCtx + } + var Params = NewGetParamParams() + if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params + o.Context.Respond(rw, r, route.Produces, route, err) + return + } + + res := o.Handler.Handle(Params) // actually handle the request + o.Context.Respond(rw, r, route.Produces, route, res) + +} diff --git a/pkg/gen/ghcapi/ghcoperations/application_parameters/get_param_parameters.go b/pkg/gen/ghcapi/ghcoperations/application_parameters/get_param_parameters.go new file mode 100644 index 00000000000..8c05fe5ad84 --- /dev/null +++ b/pkg/gen/ghcapi/ghcoperations/application_parameters/get_param_parameters.go @@ -0,0 +1,71 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package application_parameters + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "net/http" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime/middleware" + "github.com/go-openapi/strfmt" +) + +// NewGetParamParams creates a new GetParamParams object +// +// There are no default values defined in the spec. +func NewGetParamParams() GetParamParams { + + return GetParamParams{} +} + +// GetParamParams contains all the bound params for the get param operation +// typically these are obtained from a http.Request +// +// swagger:parameters getParam +type GetParamParams struct { + + // HTTP Request Object + HTTPRequest *http.Request `json:"-"` + + /*Parameter Name + Required: true + In: path + */ + ParameterName string +} + +// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface +// for simple values it will use straight method calls. +// +// To ensure default values, the struct must have been initialized with NewGetParamParams() beforehand. +func (o *GetParamParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error { + var res []error + + o.HTTPRequest = r + + rParameterName, rhkParameterName, _ := route.Params.GetOK("parameterName") + if err := o.bindParameterName(rParameterName, rhkParameterName, route.Formats); err != nil { + res = append(res, err) + } + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +// bindParameterName binds and validates parameter ParameterName from path. +func (o *GetParamParams) bindParameterName(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: true + // Parameter is provided by construction from the route + o.ParameterName = raw + + return nil +} diff --git a/pkg/gen/ghcapi/ghcoperations/application_parameters/get_param_responses.go b/pkg/gen/ghcapi/ghcoperations/application_parameters/get_param_responses.go new file mode 100644 index 00000000000..5baf105818f --- /dev/null +++ b/pkg/gen/ghcapi/ghcoperations/application_parameters/get_param_responses.go @@ -0,0 +1,134 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package application_parameters + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "net/http" + + "github.com/go-openapi/runtime" + + "github.com/transcom/mymove/pkg/gen/ghcmessages" +) + +// GetParamOKCode is the HTTP code returned for type GetParamOK +const GetParamOKCode int = 200 + +/* +GetParamOK Application Parameters + +swagger:response getParamOK +*/ +type GetParamOK struct { + + /* + In: Body + */ + Payload *ghcmessages.ApplicationParameters `json:"body,omitempty"` +} + +// NewGetParamOK creates GetParamOK with default headers values +func NewGetParamOK() *GetParamOK { + + return &GetParamOK{} +} + +// WithPayload adds the payload to the get param o k response +func (o *GetParamOK) WithPayload(payload *ghcmessages.ApplicationParameters) *GetParamOK { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the get param o k response +func (o *GetParamOK) SetPayload(payload *ghcmessages.ApplicationParameters) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *GetParamOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(200) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} + +// GetParamBadRequestCode is the HTTP code returned for type GetParamBadRequest +const GetParamBadRequestCode int = 400 + +/* +GetParamBadRequest invalid request + +swagger:response getParamBadRequest +*/ +type GetParamBadRequest struct { +} + +// NewGetParamBadRequest creates GetParamBadRequest with default headers values +func NewGetParamBadRequest() *GetParamBadRequest { + + return &GetParamBadRequest{} +} + +// WriteResponse to the client +func (o *GetParamBadRequest) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.Header().Del(runtime.HeaderContentType) //Remove Content-Type on empty responses + + rw.WriteHeader(400) +} + +// GetParamUnauthorizedCode is the HTTP code returned for type GetParamUnauthorized +const GetParamUnauthorizedCode int = 401 + +/* +GetParamUnauthorized request requires user authentication + +swagger:response getParamUnauthorized +*/ +type GetParamUnauthorized struct { +} + +// NewGetParamUnauthorized creates GetParamUnauthorized with default headers values +func NewGetParamUnauthorized() *GetParamUnauthorized { + + return &GetParamUnauthorized{} +} + +// WriteResponse to the client +func (o *GetParamUnauthorized) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.Header().Del(runtime.HeaderContentType) //Remove Content-Type on empty responses + + rw.WriteHeader(401) +} + +// GetParamInternalServerErrorCode is the HTTP code returned for type GetParamInternalServerError +const GetParamInternalServerErrorCode int = 500 + +/* +GetParamInternalServerError server error + +swagger:response getParamInternalServerError +*/ +type GetParamInternalServerError struct { +} + +// NewGetParamInternalServerError creates GetParamInternalServerError with default headers values +func NewGetParamInternalServerError() *GetParamInternalServerError { + + return &GetParamInternalServerError{} +} + +// WriteResponse to the client +func (o *GetParamInternalServerError) 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/gen/ghcapi/ghcoperations/application_parameters/get_param_urlbuilder.go b/pkg/gen/ghcapi/ghcoperations/application_parameters/get_param_urlbuilder.go new file mode 100644 index 00000000000..0f41a2ec1f5 --- /dev/null +++ b/pkg/gen/ghcapi/ghcoperations/application_parameters/get_param_urlbuilder.go @@ -0,0 +1,99 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package application_parameters + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the generate command + +import ( + "errors" + "net/url" + golangswaggerpaths "path" + "strings" +) + +// GetParamURL generates an URL for the get param operation +type GetParamURL struct { + ParameterName string + + _basePath string + // avoid unkeyed usage + _ struct{} +} + +// WithBasePath sets the base path for this url builder, only required when it's different from the +// base path specified in the swagger spec. +// When the value of the base path is an empty string +func (o *GetParamURL) WithBasePath(bp string) *GetParamURL { + o.SetBasePath(bp) + return o +} + +// SetBasePath sets the base path for this url builder, only required when it's different from the +// base path specified in the swagger spec. +// When the value of the base path is an empty string +func (o *GetParamURL) SetBasePath(bp string) { + o._basePath = bp +} + +// Build a url path and query string +func (o *GetParamURL) Build() (*url.URL, error) { + var _result url.URL + + var _path = "/application_parameters/{parameterName}" + + parameterName := o.ParameterName + if parameterName != "" { + _path = strings.Replace(_path, "{parameterName}", parameterName, -1) + } else { + return nil, errors.New("parameterName is required on GetParamURL") + } + + _basePath := o._basePath + if _basePath == "" { + _basePath = "/ghc/v1" + } + _result.Path = golangswaggerpaths.Join(_basePath, _path) + + return &_result, nil +} + +// Must is a helper function to panic when the url builder returns an error +func (o *GetParamURL) Must(u *url.URL, err error) *url.URL { + if err != nil { + panic(err) + } + if u == nil { + panic("url can't be nil") + } + return u +} + +// String returns the string representation of the path with query string +func (o *GetParamURL) String() string { + return o.Must(o.Build()).String() +} + +// BuildFull builds a full url with scheme, host, path and query string +func (o *GetParamURL) BuildFull(scheme, host string) (*url.URL, error) { + if scheme == "" { + return nil, errors.New("scheme is required for a full url on GetParamURL") + } + if host == "" { + return nil, errors.New("host is required for a full url on GetParamURL") + } + + base, err := o.Build() + if err != nil { + return nil, err + } + + base.Scheme = scheme + base.Host = host + return base, nil +} + +// StringFull returns the string representation of a complete url +func (o *GetParamURL) StringFull(scheme, host string) string { + return o.Must(o.BuildFull(scheme, host)).String() +} diff --git a/pkg/gen/ghcapi/ghcoperations/mymove_api.go b/pkg/gen/ghcapi/ghcoperations/mymove_api.go index ecaced2a301..935729b2b24 100644 --- a/pkg/gen/ghcapi/ghcoperations/mymove_api.go +++ b/pkg/gen/ghcapi/ghcoperations/mymove_api.go @@ -19,6 +19,7 @@ import ( "github.com/go-openapi/strfmt" "github.com/go-openapi/swag" + "github.com/transcom/mymove/pkg/gen/ghcapi/ghcoperations/application_parameters" "github.com/transcom/mymove/pkg/gen/ghcapi/ghcoperations/customer" "github.com/transcom/mymove/pkg/gen/ghcapi/ghcoperations/customer_support_remarks" "github.com/transcom/mymove/pkg/gen/ghcapi/ghcoperations/evaluation_reports" @@ -183,6 +184,9 @@ func NewMymoveAPI(spec *loads.Document) *MymoveAPI { PwsViolationsGetPWSViolationsHandler: pws_violations.GetPWSViolationsHandlerFunc(func(params pws_violations.GetPWSViolationsParams) middleware.Responder { return middleware.NotImplemented("operation pws_violations.GetPWSViolations has not yet been implemented") }), + ApplicationParametersGetParamHandler: application_parameters.GetParamHandlerFunc(func(params application_parameters.GetParamParams) middleware.Responder { + return middleware.NotImplemented("operation application_parameters.GetParam has not yet been implemented") + }), PaymentRequestsGetPaymentRequestHandler: payment_requests.GetPaymentRequestHandlerFunc(func(params payment_requests.GetPaymentRequestParams) middleware.Responder { return middleware.NotImplemented("operation payment_requests.GetPaymentRequest has not yet been implemented") }), @@ -442,6 +446,8 @@ type MymoveAPI struct { PpmGetPPMDocumentsHandler ppm.GetPPMDocumentsHandler // PwsViolationsGetPWSViolationsHandler sets the operation handler for the get p w s violations operation PwsViolationsGetPWSViolationsHandler pws_violations.GetPWSViolationsHandler + // ApplicationParametersGetParamHandler sets the operation handler for the get param operation + ApplicationParametersGetParamHandler application_parameters.GetParamHandler // PaymentRequestsGetPaymentRequestHandler sets the operation handler for the get payment request operation PaymentRequestsGetPaymentRequestHandler payment_requests.GetPaymentRequestHandler // PaymentRequestsGetPaymentRequestsForMoveHandler sets the operation handler for the get payment requests for move operation @@ -732,6 +738,9 @@ func (o *MymoveAPI) Validate() error { if o.PwsViolationsGetPWSViolationsHandler == nil { unregistered = append(unregistered, "pws_violations.GetPWSViolationsHandler") } + if o.ApplicationParametersGetParamHandler == nil { + unregistered = append(unregistered, "application_parameters.GetParamHandler") + } if o.PaymentRequestsGetPaymentRequestHandler == nil { unregistered = append(unregistered, "payment_requests.GetPaymentRequestHandler") } @@ -1118,6 +1127,10 @@ func (o *MymoveAPI) initHandlerCache() { if o.handlers["GET"] == nil { o.handlers["GET"] = make(map[string]http.Handler) } + o.handlers["GET"]["/application_parameters/{parameterName}"] = application_parameters.NewGetParam(o.context, o.ApplicationParametersGetParamHandler) + if o.handlers["GET"] == nil { + o.handlers["GET"] = make(map[string]http.Handler) + } o.handlers["GET"]["/payment-requests/{paymentRequestID}"] = payment_requests.NewGetPaymentRequest(o.context, o.PaymentRequestsGetPaymentRequestHandler) if o.handlers["GET"] == nil { o.handlers["GET"] = make(map[string]http.Handler) diff --git a/pkg/gen/ghcmessages/application_parameters.go b/pkg/gen/ghcmessages/application_parameters.go new file mode 100644 index 00000000000..402787d4328 --- /dev/null +++ b/pkg/gen/ghcmessages/application_parameters.go @@ -0,0 +1,56 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ghcmessages + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// ApplicationParameters application parameters +// +// swagger:model ApplicationParameters +type ApplicationParameters struct { + + // parameter name + ParameterName *string `json:"parameterName,omitempty"` + + // parameter value + ParameterValue *string `json:"parameterValue,omitempty"` + + // validation code + ValidationCode *string `json:"validationCode,omitempty"` +} + +// Validate validates this application parameters +func (m *ApplicationParameters) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this application parameters based on context it is used +func (m *ApplicationParameters) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *ApplicationParameters) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *ApplicationParameters) UnmarshalBinary(b []byte) error { + var res ApplicationParameters + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/gen/ghcmessages/customer.go b/pkg/gen/ghcmessages/customer.go index ec607140830..9bde67a3d18 100644 --- a/pkg/gen/ghcmessages/customer.go +++ b/pkg/gen/ghcmessages/customer.go @@ -29,7 +29,7 @@ type Customer struct { BackupContact *BackupContact `json:"backup_contact,omitempty"` // cac validated - CacValidated bool `json:"cacValidated,omitempty"` + CacValidated *bool `json:"cacValidated,omitempty"` // current address CurrentAddress *Address `json:"current_address,omitempty"` diff --git a/pkg/gen/ghcmessages/m_t_o_service_item.go b/pkg/gen/ghcmessages/m_t_o_service_item.go index e2c69984b79..da5bb6ca9df 100644 --- a/pkg/gen/ghcmessages/m_t_o_service_item.go +++ b/pkg/gen/ghcmessages/m_t_o_service_item.go @@ -55,6 +55,9 @@ type MTOServiceItem struct { // e tag ETag string `json:"eTag,omitempty"` + // estimated price + EstimatedPrice *int64 `json:"estimatedPrice,omitempty"` + // estimated weight of the shuttle service item provided by the prime // Example: 2500 EstimatedWeight *int64 `json:"estimatedWeight,omitempty"` @@ -150,6 +153,9 @@ type MTOServiceItem struct { // Format: date SitRequestedDelivery *strfmt.Date `json:"sitRequestedDelivery,omitempty"` + // standalone crate + StandaloneCrate *bool `json:"standaloneCrate,omitempty"` + // status Status MTOServiceItemStatus `json:"status,omitempty"` diff --git a/pkg/gen/ghcmessages/moving_expense.go b/pkg/gen/ghcmessages/moving_expense.go index 323b30e24e9..d4b571d2230 100644 --- a/pkg/gen/ghcmessages/moving_expense.go +++ b/pkg/gen/ghcmessages/moving_expense.go @@ -77,6 +77,9 @@ type MovingExpense struct { // Format: date SitEndDate *strfmt.Date `json:"sitEndDate"` + // sit location + SitLocation *SITLocationType `json:"sitLocation,omitempty"` + // The date the shipment entered storage, applicable for the `STORAGE` movingExpenseType only // Example: 2022-04-26 // Format: date @@ -131,6 +134,10 @@ func (m *MovingExpense) Validate(formats strfmt.Registry) error { res = append(res, err) } + if err := m.validateSitLocation(formats); err != nil { + res = append(res, err) + } + if err := m.validateSitStartDate(formats); err != nil { res = append(res, err) } @@ -271,6 +278,25 @@ func (m *MovingExpense) validateSitEndDate(formats strfmt.Registry) error { return nil } +func (m *MovingExpense) validateSitLocation(formats strfmt.Registry) error { + if swag.IsZero(m.SitLocation) { // not required + return nil + } + + if m.SitLocation != nil { + if err := m.SitLocation.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("sitLocation") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("sitLocation") + } + return err + } + } + + return nil +} + func (m *MovingExpense) validateSitStartDate(formats strfmt.Registry) error { if swag.IsZero(m.SitStartDate) { // not required return nil @@ -351,6 +377,10 @@ func (m *MovingExpense) ContextValidate(ctx context.Context, formats strfmt.Regi res = append(res, err) } + if err := m.contextValidateSitLocation(ctx, formats); err != nil { + res = append(res, err) + } + if err := m.contextValidateStatus(ctx, formats); err != nil { res = append(res, err) } @@ -469,6 +499,27 @@ func (m *MovingExpense) contextValidateReason(ctx context.Context, formats strfm return nil } +func (m *MovingExpense) contextValidateSitLocation(ctx context.Context, formats strfmt.Registry) error { + + if m.SitLocation != nil { + + if swag.IsZero(m.SitLocation) { // not required + return nil + } + + if err := m.SitLocation.ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("sitLocation") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("sitLocation") + } + return err + } + } + + return nil +} + func (m *MovingExpense) contextValidateStatus(ctx context.Context, formats strfmt.Registry) error { if m.Status != nil { diff --git a/pkg/gen/ghcmessages/p_p_m_shipment_status.go b/pkg/gen/ghcmessages/p_p_m_shipment_status.go index d924141476c..f976a0c7c5c 100644 --- a/pkg/gen/ghcmessages/p_p_m_shipment_status.go +++ b/pkg/gen/ghcmessages/p_p_m_shipment_status.go @@ -19,8 +19,8 @@ import ( // - **SUBMITTED**: The shipment belongs to a move that has been submitted by the customer or has been created by a Service Counselor or Prime Contractor for a submitted move. // - **WAITING_ON_CUSTOMER**: The PPM shipment has been approved and the customer may now provide their actual move closeout information and documentation required to get paid. // - **NEEDS_ADVANCE_APPROVAL**: The shipment was counseled by the Prime Contractor and approved but an advance was requested so will need further financial approval from the government. -// - **NEEDS_PAYMENT_APPROVAL**: The customer has provided their closeout weight tickets, receipts, and expenses and certified it for the Service Counselor to approve, exclude or reject. -// - **PAYMENT_APPROVED**: The Service Counselor has reviewed all of the customer's PPM closeout documentation and authorizes the customer can download and submit their finalized SSW packet. +// - **NEEDS_CLOSEOUT**: The customer has provided their closeout weight tickets, receipts, and expenses and certified it for the Service Counselor to approve, exclude or reject. +// - **CLOSEOUT_COMPLETE**: The Service Counselor has reviewed all of the customer's PPM closeout documentation and authorizes the customer can download and submit their finalized SSW packet. // // swagger:model PPMShipmentStatus type PPMShipmentStatus string @@ -48,11 +48,11 @@ const ( // PPMShipmentStatusNEEDSADVANCEAPPROVAL captures enum value "NEEDS_ADVANCE_APPROVAL" PPMShipmentStatusNEEDSADVANCEAPPROVAL PPMShipmentStatus = "NEEDS_ADVANCE_APPROVAL" - // PPMShipmentStatusNEEDSPAYMENTAPPROVAL captures enum value "NEEDS_PAYMENT_APPROVAL" - PPMShipmentStatusNEEDSPAYMENTAPPROVAL PPMShipmentStatus = "NEEDS_PAYMENT_APPROVAL" + // PPMShipmentStatusNEEDSCLOSEOUT captures enum value "NEEDS_CLOSEOUT" + PPMShipmentStatusNEEDSCLOSEOUT PPMShipmentStatus = "NEEDS_CLOSEOUT" - // PPMShipmentStatusPAYMENTAPPROVED captures enum value "PAYMENT_APPROVED" - PPMShipmentStatusPAYMENTAPPROVED PPMShipmentStatus = "PAYMENT_APPROVED" + // PPMShipmentStatusCLOSEOUTCOMPLETE captures enum value "CLOSEOUT_COMPLETE" + PPMShipmentStatusCLOSEOUTCOMPLETE PPMShipmentStatus = "CLOSEOUT_COMPLETE" ) // for schema @@ -60,7 +60,7 @@ var pPMShipmentStatusEnum []interface{} func init() { var res []PPMShipmentStatus - if err := json.Unmarshal([]byte(`["DRAFT","SUBMITTED","WAITING_ON_CUSTOMER","NEEDS_ADVANCE_APPROVAL","NEEDS_PAYMENT_APPROVAL","PAYMENT_APPROVED"]`), &res); err != nil { + if err := json.Unmarshal([]byte(`["DRAFT","SUBMITTED","WAITING_ON_CUSTOMER","NEEDS_ADVANCE_APPROVAL","NEEDS_CLOSEOUT","CLOSEOUT_COMPLETE"]`), &res); err != nil { panic(err) } for _, v := range res { diff --git a/pkg/gen/ghcmessages/service_item_param_name.go b/pkg/gen/ghcmessages/service_item_param_name.go index e1f416f41d1..dd10c8003cd 100644 --- a/pkg/gen/ghcmessages/service_item_param_name.go +++ b/pkg/gen/ghcmessages/service_item_param_name.go @@ -227,6 +227,15 @@ const ( // ServiceItemParamNameZipSITOriginHHGOriginalAddress captures enum value "ZipSITOriginHHGOriginalAddress" ServiceItemParamNameZipSITOriginHHGOriginalAddress ServiceItemParamName = "ZipSITOriginHHGOriginalAddress" + + // ServiceItemParamNameStandaloneCrate captures enum value "StandaloneCrate" + ServiceItemParamNameStandaloneCrate ServiceItemParamName = "StandaloneCrate" + + // ServiceItemParamNameStandaloneCrateCap captures enum value "StandaloneCrateCap" + ServiceItemParamNameStandaloneCrateCap ServiceItemParamName = "StandaloneCrateCap" + + // ServiceItemParamNameUncappedRequestTotal captures enum value "UncappedRequestTotal" + ServiceItemParamNameUncappedRequestTotal ServiceItemParamName = "UncappedRequestTotal" ) // for schema @@ -234,7 +243,7 @@ var serviceItemParamNameEnum []interface{} func init() { var res []ServiceItemParamName - if err := json.Unmarshal([]byte(`["ActualPickupDate","ContractCode","ContractYearName","CubicFeetBilled","CubicFeetCrating","DimensionHeight","DimensionLength","DimensionWidth","DistanceZip","DistanceZipSITDest","DistanceZipSITOrigin","EIAFuelPrice","EscalationCompounded","FSCMultiplier","FSCPriceDifferenceInCents","FSCWeightBasedDistanceMultiplier","IsPeak","MarketDest","MarketOrigin","MTOAvailableToPrimeAt","NTSPackingFactor","NumberDaysSIT","PriceAreaDest","PriceAreaIntlDest","PriceAreaIntlOrigin","PriceAreaOrigin","PriceRateOrFactor","PSI_LinehaulDom","PSI_LinehaulDomPrice","PSI_LinehaulShort","PSI_LinehaulShortPrice","PSI_PriceDomDest","PSI_PriceDomDestPrice","PSI_PriceDomOrigin","PSI_PriceDomOriginPrice","PSI_ShippingLinehaulIntlCO","PSI_ShippingLinehaulIntlCOPrice","PSI_ShippingLinehaulIntlOC","PSI_ShippingLinehaulIntlOCPrice","PSI_ShippingLinehaulIntlOO","PSI_ShippingLinehaulIntlOOPrice","RateAreaNonStdDest","RateAreaNonStdOrigin","ReferenceDate","RequestedPickupDate","ServiceAreaDest","ServiceAreaOrigin","ServicesScheduleDest","ServicesScheduleOrigin","SITPaymentRequestEnd","SITPaymentRequestStart","SITScheduleDest","SITScheduleOrigin","SITServiceAreaDest","SITServiceAreaOrigin","WeightAdjusted","WeightBilled","WeightEstimated","WeightOriginal","WeightReweigh","ZipDestAddress","ZipPickupAddress","ZipSITDestHHGFinalAddress","ZipSITDestHHGOriginalAddress","ZipSITOriginHHGActualAddress","ZipSITOriginHHGOriginalAddress"]`), &res); err != nil { + if err := json.Unmarshal([]byte(`["ActualPickupDate","ContractCode","ContractYearName","CubicFeetBilled","CubicFeetCrating","DimensionHeight","DimensionLength","DimensionWidth","DistanceZip","DistanceZipSITDest","DistanceZipSITOrigin","EIAFuelPrice","EscalationCompounded","FSCMultiplier","FSCPriceDifferenceInCents","FSCWeightBasedDistanceMultiplier","IsPeak","MarketDest","MarketOrigin","MTOAvailableToPrimeAt","NTSPackingFactor","NumberDaysSIT","PriceAreaDest","PriceAreaIntlDest","PriceAreaIntlOrigin","PriceAreaOrigin","PriceRateOrFactor","PSI_LinehaulDom","PSI_LinehaulDomPrice","PSI_LinehaulShort","PSI_LinehaulShortPrice","PSI_PriceDomDest","PSI_PriceDomDestPrice","PSI_PriceDomOrigin","PSI_PriceDomOriginPrice","PSI_ShippingLinehaulIntlCO","PSI_ShippingLinehaulIntlCOPrice","PSI_ShippingLinehaulIntlOC","PSI_ShippingLinehaulIntlOCPrice","PSI_ShippingLinehaulIntlOO","PSI_ShippingLinehaulIntlOOPrice","RateAreaNonStdDest","RateAreaNonStdOrigin","ReferenceDate","RequestedPickupDate","ServiceAreaDest","ServiceAreaOrigin","ServicesScheduleDest","ServicesScheduleOrigin","SITPaymentRequestEnd","SITPaymentRequestStart","SITScheduleDest","SITScheduleOrigin","SITServiceAreaDest","SITServiceAreaOrigin","WeightAdjusted","WeightBilled","WeightEstimated","WeightOriginal","WeightReweigh","ZipDestAddress","ZipPickupAddress","ZipSITDestHHGFinalAddress","ZipSITDestHHGOriginalAddress","ZipSITOriginHHGActualAddress","ZipSITOriginHHGOriginalAddress","StandaloneCrate","StandaloneCrateCap","UncappedRequestTotal"]`), &res); err != nil { panic(err) } for _, v := range res { diff --git a/pkg/gen/ghcmessages/update_moving_expense.go b/pkg/gen/ghcmessages/update_moving_expense.go index c9ae28b486e..e6178a17853 100644 --- a/pkg/gen/ghcmessages/update_moving_expense.go +++ b/pkg/gen/ghcmessages/update_moving_expense.go @@ -35,6 +35,9 @@ type UpdateMovingExpense struct { // Format: date SitEndDate strfmt.Date `json:"sitEndDate,omitempty"` + // sit location + SitLocation *SITLocationType `json:"sitLocation,omitempty"` + // The date the shipment entered storage, applicable for the `STORAGE` movingExpenseType only // Format: date SitStartDate strfmt.Date `json:"sitStartDate,omitempty"` @@ -58,6 +61,10 @@ func (m *UpdateMovingExpense) Validate(formats strfmt.Registry) error { res = append(res, err) } + if err := m.validateSitLocation(formats); err != nil { + res = append(res, err) + } + if err := m.validateSitStartDate(formats); err != nil { res = append(res, err) } @@ -103,6 +110,25 @@ func (m *UpdateMovingExpense) validateSitEndDate(formats strfmt.Registry) error return nil } +func (m *UpdateMovingExpense) validateSitLocation(formats strfmt.Registry) error { + if swag.IsZero(m.SitLocation) { // not required + return nil + } + + if m.SitLocation != nil { + if err := m.SitLocation.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("sitLocation") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("sitLocation") + } + return err + } + } + + return nil +} + func (m *UpdateMovingExpense) validateSitStartDate(formats strfmt.Registry) error { if swag.IsZero(m.SitStartDate) { // not required return nil @@ -140,6 +166,10 @@ func (m *UpdateMovingExpense) ContextValidate(ctx context.Context, formats strfm res = append(res, err) } + if err := m.contextValidateSitLocation(ctx, formats); err != nil { + res = append(res, err) + } + if err := m.contextValidateStatus(ctx, formats); err != nil { res = append(res, err) } @@ -171,6 +201,27 @@ func (m *UpdateMovingExpense) contextValidateMovingExpenseType(ctx context.Conte return nil } +func (m *UpdateMovingExpense) contextValidateSitLocation(ctx context.Context, formats strfmt.Registry) error { + + if m.SitLocation != nil { + + if swag.IsZero(m.SitLocation) { // not required + return nil + } + + if err := m.SitLocation.ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("sitLocation") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("sitLocation") + } + return err + } + } + + return nil +} + func (m *UpdateMovingExpense) contextValidateStatus(ctx context.Context, formats strfmt.Registry) error { if swag.IsZero(m.Status) { // not required diff --git a/pkg/gen/internalapi/embedded_spec.go b/pkg/gen/internalapi/embedded_spec.go index 021c9dc24b2..bff54263ca8 100644 --- a/pkg/gen/internalapi/embedded_spec.go +++ b/pkg/gen/internalapi/embedded_spec.go @@ -3061,6 +3061,13 @@ func init() { "description": "ID of the order that the upload belongs to", "name": "orderId", "in": "query" + }, + { + "type": "string", + "format": "uuid", + "description": "Optional PPM shipment ID related to the upload", + "name": "ppmId", + "in": "query" } ], "responses": { @@ -4996,6 +5003,19 @@ func init() { "x-omitempty": false, "example": "2018-05-26" }, + "sitLocation": { + "allOf": [ + { + "$ref": "#/definitions/SITLocationType" + }, + { + "x-nullable": true + }, + { + "x-omitempty": false + } + ] + }, "sitStartDate": { "description": "The date the shipment entered storage, applicable for the ` + "`" + `STORAGE` + "`" + ` movingExpenseType only", "type": "string", @@ -5812,50 +5832,50 @@ func init() { "x-nullable": true, "x-omitempty": false }, - "tertiaryDestinationAddress": { - "allOf": [ - { - "$ref": "#/definitions/Address" - }, - { - "x-nullable": true - }, - { - "x-omitempty": false - } - ] - }, - "tertiaryDestinationPostalCode": { - "type": "string", - "format": "An optional secondary pickup location near the origin where additional goods exist.", - "title": "ZIP", - "pattern": "^(\\d{5})$", - "x-nullable": true, - "x-omitempty": false, - "example": "90210" - }, - "tertiaryPickupAddress": { - "allOf": [ - { - "$ref": "#/definitions/Address" - }, - { - "x-nullable": true - }, - { - "x-omitempty": false - } - ] - }, - "tertiaryPickupPostalCode": { - "type": "string", - "format": "An optional secondary pickup location near the origin where additional goods exist.", - "title": "ZIP", - "pattern": "^(\\d{5})$", - "x-nullable": true, - "x-omitempty": false, - "example": "90210" - }, + "tertiaryDestinationAddress": { + "allOf": [ + { + "$ref": "#/definitions/Address" + }, + { + "x-nullable": true + }, + { + "x-omitempty": false + } + ] + }, + "tertiaryDestinationPostalCode": { + "type": "string", + "format": "An optional secondary pickup location near the origin where additional goods exist.", + "title": "ZIP", + "pattern": "^(\\d{5})$", + "x-nullable": true, + "x-omitempty": false, + "example": "90210" + }, + "tertiaryPickupAddress": { + "allOf": [ + { + "$ref": "#/definitions/Address" + }, + { + "x-nullable": true + }, + { + "x-omitempty": false + } + ] + }, + "tertiaryPickupPostalCode": { + "type": "string", + "format": "An optional secondary pickup location near the origin where additional goods exist.", + "title": "ZIP", + "pattern": "^(\\d{5})$", + "x-nullable": true, + "x-omitempty": false, + "example": "90210" + }, "updatedAt": { "description": "Timestamp of when a property of this object was last updated (UTC)", "type": "string", @@ -5873,15 +5893,15 @@ func init() { "x-nullable": true }, "PPMShipmentStatus": { - "description": "Status of the PPM Shipment:\n * **DRAFT**: The customer has created the PPM shipment but has not yet submitted their move for counseling.\n * **SUBMITTED**: The shipment belongs to a move that has been submitted by the customer or has been created by a Service Counselor or Prime Contractor for a submitted move.\n * **WAITING_ON_CUSTOMER**: The PPM shipment has been approved and the customer may now provide their actual move closeout information and documentation required to get paid.\n * **NEEDS_ADVANCE_APPROVAL**: The shipment was counseled by the Prime Contractor and approved but an advance was requested so will need further financial approval from the government.\n * **NEEDS_PAYMENT_APPROVAL**: The customer has provided their closeout weight tickets, receipts, and expenses and certified it for the Service Counselor to approve, exclude or reject.\n * **PAYMENT_APPROVED**: The Service Counselor has reviewed all of the customer's PPM closeout documentation and authorizes the customer can download and submit their finalized SSW packet.\n", + "description": "Status of the PPM Shipment:\n * **DRAFT**: The customer has created the PPM shipment but has not yet submitted their move for counseling.\n * **SUBMITTED**: The shipment belongs to a move that has been submitted by the customer or has been created by a Service Counselor or Prime Contractor for a submitted move.\n * **WAITING_ON_CUSTOMER**: The PPM shipment has been approved and the customer may now provide their actual move closeout information and documentation required to get paid.\n * **NEEDS_ADVANCE_APPROVAL**: The shipment was counseled by the Prime Contractor and approved but an advance was requested so will need further financial approval from the government.\n * **NEEDS_CLOSEOUT**: The customer has provided their closeout weight tickets, receipts, and expenses and certified it for the Service Counselor to approve, exclude or reject.\n * **CLOSEOUT_COMPLETE**: The Service Counselor has reviewed all of the customer's PPM closeout documentation and authorizes the customer can download and submit their finalized SSW packet.\n", "type": "string", "enum": [ "DRAFT", "SUBMITTED", "WAITING_ON_CUSTOMER", "NEEDS_ADVANCE_APPROVAL", - "NEEDS_PAYMENT_APPROVAL", - "PAYMENT_APPROVED" + "NEEDS_CLOSEOUT", + "CLOSEOUT_COMPLETE" ], "readOnly": true }, @@ -6725,6 +6745,16 @@ func init() { "type": "string", "format": "date" }, + "sitLocation": { + "allOf": [ + { + "$ref": "#/definitions/SITLocationType" + }, + { + "x-nullable": true + } + ] + }, "sitStartDate": { "description": "The date the shipment entered storage, applicable for the ` + "`" + `STORAGE` + "`" + ` movingExpenseType only", "type": "string", @@ -11039,6 +11069,13 @@ func init() { "description": "ID of the order that the upload belongs to", "name": "orderId", "in": "query" + }, + { + "type": "string", + "format": "uuid", + "description": "Optional PPM shipment ID related to the upload", + "name": "ppmId", + "in": "query" } ], "responses": { @@ -12978,6 +13015,19 @@ func init() { "x-omitempty": false, "example": "2018-05-26" }, + "sitLocation": { + "allOf": [ + { + "$ref": "#/definitions/SITLocationType" + }, + { + "x-nullable": true + }, + { + "x-omitempty": false + } + ] + }, "sitStartDate": { "description": "The date the shipment entered storage, applicable for the ` + "`" + `STORAGE` + "`" + ` movingExpenseType only", "type": "string", @@ -13795,49 +13845,49 @@ func init() { "x-omitempty": false }, "tertiaryDestinationAddress": { - "allOf": [ - { - "$ref": "#/definitions/Address" - }, - { - "x-nullable": true - }, - { - "x-omitempty": false - } - ] - }, - "tertiaryDestinationPostalCode": { - "type": "string", - "format": "An optional secondary pickup location near the origin where additional goods exist.", - "title": "ZIP", - "pattern": "^(\\d{5})$", - "x-nullable": true, - "x-omitempty": false, - "example": "90210" - }, - "tertiaryPickupAddress": { - "allOf": [ - { - "$ref": "#/definitions/Address" - }, - { - "x-nullable": true - }, - { - "x-omitempty": false - } - ] - }, - "tertiaryPickupPostalCode": { - "type": "string", - "format": "An optional secondary pickup location near the origin where additional goods exist.", - "title": "ZIP", - "pattern": "^(\\d{5})$", - "x-nullable": true, - "x-omitempty": false, - "example": "90210" - }, + "allOf": [ + { + "$ref": "#/definitions/Address" + }, + { + "x-nullable": true + }, + { + "x-omitempty": false + } + ] + }, + "tertiaryDestinationPostalCode": { + "type": "string", + "format": "An optional secondary pickup location near the origin where additional goods exist.", + "title": "ZIP", + "pattern": "^(\\d{5})$", + "x-nullable": true, + "x-omitempty": false, + "example": "90210" + }, + "tertiaryPickupAddress": { + "allOf": [ + { + "$ref": "#/definitions/Address" + }, + { + "x-nullable": true + }, + { + "x-omitempty": false + } + ] + }, + "tertiaryPickupPostalCode": { + "type": "string", + "format": "An optional secondary pickup location near the origin where additional goods exist.", + "title": "ZIP", + "pattern": "^(\\d{5})$", + "x-nullable": true, + "x-omitempty": false, + "example": "90210" + }, "updatedAt": { "description": "Timestamp of when a property of this object was last updated (UTC)", "type": "string", @@ -13855,15 +13905,15 @@ func init() { "x-nullable": true }, "PPMShipmentStatus": { - "description": "Status of the PPM Shipment:\n * **DRAFT**: The customer has created the PPM shipment but has not yet submitted their move for counseling.\n * **SUBMITTED**: The shipment belongs to a move that has been submitted by the customer or has been created by a Service Counselor or Prime Contractor for a submitted move.\n * **WAITING_ON_CUSTOMER**: The PPM shipment has been approved and the customer may now provide their actual move closeout information and documentation required to get paid.\n * **NEEDS_ADVANCE_APPROVAL**: The shipment was counseled by the Prime Contractor and approved but an advance was requested so will need further financial approval from the government.\n * **NEEDS_PAYMENT_APPROVAL**: The customer has provided their closeout weight tickets, receipts, and expenses and certified it for the Service Counselor to approve, exclude or reject.\n * **PAYMENT_APPROVED**: The Service Counselor has reviewed all of the customer's PPM closeout documentation and authorizes the customer can download and submit their finalized SSW packet.\n", + "description": "Status of the PPM Shipment:\n * **DRAFT**: The customer has created the PPM shipment but has not yet submitted their move for counseling.\n * **SUBMITTED**: The shipment belongs to a move that has been submitted by the customer or has been created by a Service Counselor or Prime Contractor for a submitted move.\n * **WAITING_ON_CUSTOMER**: The PPM shipment has been approved and the customer may now provide their actual move closeout information and documentation required to get paid.\n * **NEEDS_ADVANCE_APPROVAL**: The shipment was counseled by the Prime Contractor and approved but an advance was requested so will need further financial approval from the government.\n * **NEEDS_CLOSEOUT**: The customer has provided their closeout weight tickets, receipts, and expenses and certified it for the Service Counselor to approve, exclude or reject.\n * **CLOSEOUT_COMPLETE**: The Service Counselor has reviewed all of the customer's PPM closeout documentation and authorizes the customer can download and submit their finalized SSW packet.\n", "type": "string", "enum": [ "DRAFT", "SUBMITTED", "WAITING_ON_CUSTOMER", "NEEDS_ADVANCE_APPROVAL", - "NEEDS_PAYMENT_APPROVAL", - "PAYMENT_APPROVED" + "NEEDS_CLOSEOUT", + "CLOSEOUT_COMPLETE" ], "readOnly": true }, @@ -14708,6 +14758,16 @@ func init() { "type": "string", "format": "date" }, + "sitLocation": { + "allOf": [ + { + "$ref": "#/definitions/SITLocationType" + }, + { + "x-nullable": true + } + ] + }, "sitStartDate": { "description": "The date the shipment entered storage, applicable for the ` + "`" + `STORAGE` + "`" + ` movingExpenseType only", "type": "string", diff --git a/pkg/gen/internalapi/internaloperations/uploads/delete_upload_parameters.go b/pkg/gen/internalapi/internaloperations/uploads/delete_upload_parameters.go index 91cad5f24f6..371f160ef2e 100644 --- a/pkg/gen/internalapi/internaloperations/uploads/delete_upload_parameters.go +++ b/pkg/gen/internalapi/internaloperations/uploads/delete_upload_parameters.go @@ -36,6 +36,10 @@ type DeleteUploadParams struct { In: query */ OrderID *strfmt.UUID + /*Optional PPM shipment ID related to the upload + In: query + */ + PpmID *strfmt.UUID /*UUID of the upload to be deleted Required: true In: path @@ -59,6 +63,11 @@ func (o *DeleteUploadParams) BindRequest(r *http.Request, route *middleware.Matc res = append(res, err) } + qPpmID, qhkPpmID, _ := qs.GetOK("ppmId") + if err := o.bindPpmID(qPpmID, qhkPpmID, route.Formats); err != nil { + res = append(res, err) + } + rUploadID, rhkUploadID, _ := route.Params.GetOK("uploadId") if err := o.bindUploadID(rUploadID, rhkUploadID, route.Formats); err != nil { res = append(res, err) @@ -106,6 +115,43 @@ func (o *DeleteUploadParams) validateOrderID(formats strfmt.Registry) error { return nil } +// bindPpmID binds and validates parameter PpmID from query. +func (o *DeleteUploadParams) bindPpmID(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: false + // AllowEmptyValue: false + + if raw == "" { // empty values pass all other validations + return nil + } + + // Format: uuid + value, err := formats.Parse("uuid", raw) + if err != nil { + return errors.InvalidType("ppmId", "query", "strfmt.UUID", raw) + } + o.PpmID = (value.(*strfmt.UUID)) + + if err := o.validatePpmID(formats); err != nil { + return err + } + + return nil +} + +// validatePpmID carries on validations for parameter PpmID +func (o *DeleteUploadParams) validatePpmID(formats strfmt.Registry) error { + + if err := validate.FormatOf("ppmId", "query", "uuid", o.PpmID.String(), formats); err != nil { + return err + } + return nil +} + // bindUploadID binds and validates parameter UploadID from path. func (o *DeleteUploadParams) bindUploadID(rawData []string, hasKey bool, formats strfmt.Registry) error { var raw string diff --git a/pkg/gen/internalapi/internaloperations/uploads/delete_upload_urlbuilder.go b/pkg/gen/internalapi/internaloperations/uploads/delete_upload_urlbuilder.go index 6d0850522b1..ac38bd47b6f 100644 --- a/pkg/gen/internalapi/internaloperations/uploads/delete_upload_urlbuilder.go +++ b/pkg/gen/internalapi/internaloperations/uploads/delete_upload_urlbuilder.go @@ -19,6 +19,7 @@ type DeleteUploadURL struct { UploadID strfmt.UUID OrderID *strfmt.UUID + PpmID *strfmt.UUID _basePath string // avoid unkeyed usage @@ -69,6 +70,14 @@ func (o *DeleteUploadURL) Build() (*url.URL, error) { qs.Set("orderId", orderIDQ) } + var ppmIDQ string + if o.PpmID != nil { + ppmIDQ = o.PpmID.String() + } + if ppmIDQ != "" { + qs.Set("ppmId", ppmIDQ) + } + _result.RawQuery = qs.Encode() return &_result, nil diff --git a/pkg/gen/internalmessages/moving_expense.go b/pkg/gen/internalmessages/moving_expense.go index 89c0fb59eb5..249de7b0362 100644 --- a/pkg/gen/internalmessages/moving_expense.go +++ b/pkg/gen/internalmessages/moving_expense.go @@ -77,6 +77,9 @@ type MovingExpense struct { // Format: date SitEndDate *strfmt.Date `json:"sitEndDate"` + // sit location + SitLocation *SITLocationType `json:"sitLocation,omitempty"` + // The date the shipment entered storage, applicable for the `STORAGE` movingExpenseType only // Example: 2022-04-26 // Format: date @@ -131,6 +134,10 @@ func (m *MovingExpense) Validate(formats strfmt.Registry) error { res = append(res, err) } + if err := m.validateSitLocation(formats); err != nil { + res = append(res, err) + } + if err := m.validateSitStartDate(formats); err != nil { res = append(res, err) } @@ -271,6 +278,25 @@ func (m *MovingExpense) validateSitEndDate(formats strfmt.Registry) error { return nil } +func (m *MovingExpense) validateSitLocation(formats strfmt.Registry) error { + if swag.IsZero(m.SitLocation) { // not required + return nil + } + + if m.SitLocation != nil { + if err := m.SitLocation.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("sitLocation") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("sitLocation") + } + return err + } + } + + return nil +} + func (m *MovingExpense) validateSitStartDate(formats strfmt.Registry) error { if swag.IsZero(m.SitStartDate) { // not required return nil @@ -351,6 +377,10 @@ func (m *MovingExpense) ContextValidate(ctx context.Context, formats strfmt.Regi res = append(res, err) } + if err := m.contextValidateSitLocation(ctx, formats); err != nil { + res = append(res, err) + } + if err := m.contextValidateStatus(ctx, formats); err != nil { res = append(res, err) } @@ -469,6 +499,27 @@ func (m *MovingExpense) contextValidateReason(ctx context.Context, formats strfm return nil } +func (m *MovingExpense) contextValidateSitLocation(ctx context.Context, formats strfmt.Registry) error { + + if m.SitLocation != nil { + + if swag.IsZero(m.SitLocation) { // not required + return nil + } + + if err := m.SitLocation.ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("sitLocation") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("sitLocation") + } + return err + } + } + + return nil +} + func (m *MovingExpense) contextValidateStatus(ctx context.Context, formats strfmt.Registry) error { if m.Status != nil { diff --git a/pkg/gen/internalmessages/p_p_m_shipment_status.go b/pkg/gen/internalmessages/p_p_m_shipment_status.go index 4ce4f8b504d..f509efa3730 100644 --- a/pkg/gen/internalmessages/p_p_m_shipment_status.go +++ b/pkg/gen/internalmessages/p_p_m_shipment_status.go @@ -19,8 +19,8 @@ import ( // - **SUBMITTED**: The shipment belongs to a move that has been submitted by the customer or has been created by a Service Counselor or Prime Contractor for a submitted move. // - **WAITING_ON_CUSTOMER**: The PPM shipment has been approved and the customer may now provide their actual move closeout information and documentation required to get paid. // - **NEEDS_ADVANCE_APPROVAL**: The shipment was counseled by the Prime Contractor and approved but an advance was requested so will need further financial approval from the government. -// - **NEEDS_PAYMENT_APPROVAL**: The customer has provided their closeout weight tickets, receipts, and expenses and certified it for the Service Counselor to approve, exclude or reject. -// - **PAYMENT_APPROVED**: The Service Counselor has reviewed all of the customer's PPM closeout documentation and authorizes the customer can download and submit their finalized SSW packet. +// - **NEEDS_CLOSEOUT**: The customer has provided their closeout weight tickets, receipts, and expenses and certified it for the Service Counselor to approve, exclude or reject. +// - **CLOSEOUT_COMPLETE**: The Service Counselor has reviewed all of the customer's PPM closeout documentation and authorizes the customer can download and submit their finalized SSW packet. // // swagger:model PPMShipmentStatus type PPMShipmentStatus string @@ -48,11 +48,11 @@ const ( // PPMShipmentStatusNEEDSADVANCEAPPROVAL captures enum value "NEEDS_ADVANCE_APPROVAL" PPMShipmentStatusNEEDSADVANCEAPPROVAL PPMShipmentStatus = "NEEDS_ADVANCE_APPROVAL" - // PPMShipmentStatusNEEDSPAYMENTAPPROVAL captures enum value "NEEDS_PAYMENT_APPROVAL" - PPMShipmentStatusNEEDSPAYMENTAPPROVAL PPMShipmentStatus = "NEEDS_PAYMENT_APPROVAL" + // PPMShipmentStatusNEEDSCLOSEOUT captures enum value "NEEDS_CLOSEOUT" + PPMShipmentStatusNEEDSCLOSEOUT PPMShipmentStatus = "NEEDS_CLOSEOUT" - // PPMShipmentStatusPAYMENTAPPROVED captures enum value "PAYMENT_APPROVED" - PPMShipmentStatusPAYMENTAPPROVED PPMShipmentStatus = "PAYMENT_APPROVED" + // PPMShipmentStatusCLOSEOUTCOMPLETE captures enum value "CLOSEOUT_COMPLETE" + PPMShipmentStatusCLOSEOUTCOMPLETE PPMShipmentStatus = "CLOSEOUT_COMPLETE" ) // for schema @@ -60,7 +60,7 @@ var pPMShipmentStatusEnum []interface{} func init() { var res []PPMShipmentStatus - if err := json.Unmarshal([]byte(`["DRAFT","SUBMITTED","WAITING_ON_CUSTOMER","NEEDS_ADVANCE_APPROVAL","NEEDS_PAYMENT_APPROVAL","PAYMENT_APPROVED"]`), &res); err != nil { + if err := json.Unmarshal([]byte(`["DRAFT","SUBMITTED","WAITING_ON_CUSTOMER","NEEDS_ADVANCE_APPROVAL","NEEDS_CLOSEOUT","CLOSEOUT_COMPLETE"]`), &res); err != nil { panic(err) } for _, v := range res { diff --git a/pkg/gen/internalmessages/update_moving_expense.go b/pkg/gen/internalmessages/update_moving_expense.go index a7f3e8ef1cf..e779d570f4a 100644 --- a/pkg/gen/internalmessages/update_moving_expense.go +++ b/pkg/gen/internalmessages/update_moving_expense.go @@ -43,6 +43,9 @@ type UpdateMovingExpense struct { // Format: date SitEndDate strfmt.Date `json:"sitEndDate,omitempty"` + // sit location + SitLocation *SITLocationType `json:"sitLocation,omitempty"` + // The date the shipment entered storage, applicable for the `STORAGE` movingExpenseType only // Format: date SitStartDate strfmt.Date `json:"sitStartDate,omitempty"` @@ -79,6 +82,10 @@ func (m *UpdateMovingExpense) Validate(formats strfmt.Registry) error { res = append(res, err) } + if err := m.validateSitLocation(formats); err != nil { + res = append(res, err) + } + if err := m.validateSitStartDate(formats); err != nil { res = append(res, err) } @@ -161,6 +168,25 @@ func (m *UpdateMovingExpense) validateSitEndDate(formats strfmt.Registry) error return nil } +func (m *UpdateMovingExpense) validateSitLocation(formats strfmt.Registry) error { + if swag.IsZero(m.SitLocation) { // not required + return nil + } + + if m.SitLocation != nil { + if err := m.SitLocation.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("sitLocation") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("sitLocation") + } + return err + } + } + + return nil +} + func (m *UpdateMovingExpense) validateSitStartDate(formats strfmt.Registry) error { if swag.IsZero(m.SitStartDate) { // not required return nil @@ -181,6 +207,10 @@ func (m *UpdateMovingExpense) ContextValidate(ctx context.Context, formats strfm res = append(res, err) } + if err := m.contextValidateSitLocation(ctx, formats); err != nil { + res = append(res, err) + } + if len(res) > 0 { return errors.CompositeValidationError(res...) } @@ -204,6 +234,27 @@ func (m *UpdateMovingExpense) contextValidateMovingExpenseType(ctx context.Conte return nil } +func (m *UpdateMovingExpense) contextValidateSitLocation(ctx context.Context, formats strfmt.Registry) error { + + if m.SitLocation != nil { + + if swag.IsZero(m.SitLocation) { // not required + return nil + } + + if err := m.SitLocation.ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("sitLocation") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("sitLocation") + } + return err + } + } + + return nil +} + // MarshalBinary interface implementation func (m *UpdateMovingExpense) MarshalBinary() ([]byte, error) { if m == nil { diff --git a/pkg/gen/primeapi/embedded_spec.go b/pkg/gen/primeapi/embedded_spec.go index 747b45a8c02..82dcbe5b799 100644 --- a/pkg/gen/primeapi/embedded_spec.go +++ b/pkg/gen/primeapi/embedded_spec.go @@ -3387,15 +3387,15 @@ func init() { "x-nullable": true }, "PPMShipmentStatus": { - "description": "Status of the PPM Shipment:\n * **DRAFT**: The customer has created the PPM shipment but has not yet submitted their move for counseling.\n * **SUBMITTED**: The shipment belongs to a move that has been submitted by the customer or has been created by a Service Counselor or Prime Contractor for a submitted move.\n * **WAITING_ON_CUSTOMER**: The PPM shipment has been approved and the customer may now provide their actual move closeout information and documentation required to get paid.\n * **NEEDS_ADVANCE_APPROVAL**: The shipment was counseled by the Prime Contractor and approved but an advance was requested so will need further financial approval from the government.\n * **NEEDS_PAYMENT_APPROVAL**: The customer has provided their closeout weight tickets, receipts, and expenses and certified it for the Service Counselor to approve, exclude or reject.\n * **PAYMENT_APPROVED**: The Service Counselor has reviewed all of the customer's PPM closeout documentation and authorizes the customer can download and submit their finalized SSW packet.\n", + "description": "Status of the PPM Shipment:\n * **DRAFT**: The customer has created the PPM shipment but has not yet submitted their move for counseling.\n * **SUBMITTED**: The shipment belongs to a move that has been submitted by the customer or has been created by a Service Counselor or Prime Contractor for a submitted move.\n * **WAITING_ON_CUSTOMER**: The PPM shipment has been approved and the customer may now provide their actual move closeout information and documentation required to get paid.\n * **NEEDS_ADVANCE_APPROVAL**: The shipment was counseled by the Prime Contractor and approved but an advance was requested so will need further financial approval from the government.\n * **NEEDS_CLOSEOUT**: The customer has provided their closeout weight tickets, receipts, and expenses and certified it for the Service Counselor to approve, exclude or reject.\n * **CLOSEOUT_COMPLETE**: The Service Counselor has reviewed all of the customer's PPM closeout documentation and authorizes the customer can download and submit their finalized SSW packet.\n", "type": "string", "enum": [ "DRAFT", "SUBMITTED", "WAITING_ON_CUSTOMER", "NEEDS_ADVANCE_APPROVAL", - "NEEDS_PAYMENT_APPROVAL", - "PAYMENT_APPROVED" + "NEEDS_CLOSEOUT", + "CLOSEOUT_COMPLETE" ], "readOnly": true }, @@ -3898,7 +3898,10 @@ func init() { "ZipSITDestHHGFinalAddress", "ZipSITDestHHGOriginalAddress", "ZipSITOriginHHGActualAddress", - "ZipSITOriginHHGOriginalAddress" + "ZipSITOriginHHGOriginalAddress", + "StandaloneCrate", + "StandaloneCrateCap", + "UncappedRequestTotal" ] }, "ServiceItemParamOrigin": { @@ -4321,6 +4324,20 @@ func init() { "x-nullable": true, "x-omitempty": false }, + "actualProGearWeight": { + "description": "The actual weight of any pro gear shipped during a move.", + "type": "integer", + "minimum": 1, + "x-nullable": true, + "example": 4500 + }, + "actualSpouseProGearWeight": { + "description": "The actual weight of any pro gear shipped during a move.", + "type": "integer", + "minimum": 1, + "x-nullable": true, + "example": 4500 + }, "counselorRemarks": { "type": "string", "x-nullable": true, @@ -8551,15 +8568,15 @@ func init() { "x-nullable": true }, "PPMShipmentStatus": { - "description": "Status of the PPM Shipment:\n * **DRAFT**: The customer has created the PPM shipment but has not yet submitted their move for counseling.\n * **SUBMITTED**: The shipment belongs to a move that has been submitted by the customer or has been created by a Service Counselor or Prime Contractor for a submitted move.\n * **WAITING_ON_CUSTOMER**: The PPM shipment has been approved and the customer may now provide their actual move closeout information and documentation required to get paid.\n * **NEEDS_ADVANCE_APPROVAL**: The shipment was counseled by the Prime Contractor and approved but an advance was requested so will need further financial approval from the government.\n * **NEEDS_PAYMENT_APPROVAL**: The customer has provided their closeout weight tickets, receipts, and expenses and certified it for the Service Counselor to approve, exclude or reject.\n * **PAYMENT_APPROVED**: The Service Counselor has reviewed all of the customer's PPM closeout documentation and authorizes the customer can download and submit their finalized SSW packet.\n", + "description": "Status of the PPM Shipment:\n * **DRAFT**: The customer has created the PPM shipment but has not yet submitted their move for counseling.\n * **SUBMITTED**: The shipment belongs to a move that has been submitted by the customer or has been created by a Service Counselor or Prime Contractor for a submitted move.\n * **WAITING_ON_CUSTOMER**: The PPM shipment has been approved and the customer may now provide their actual move closeout information and documentation required to get paid.\n * **NEEDS_ADVANCE_APPROVAL**: The shipment was counseled by the Prime Contractor and approved but an advance was requested so will need further financial approval from the government.\n * **NEEDS_CLOSEOUT**: The customer has provided their closeout weight tickets, receipts, and expenses and certified it for the Service Counselor to approve, exclude or reject.\n * **CLOSEOUT_COMPLETE**: The Service Counselor has reviewed all of the customer's PPM closeout documentation and authorizes the customer can download and submit their finalized SSW packet.\n", "type": "string", "enum": [ "DRAFT", "SUBMITTED", "WAITING_ON_CUSTOMER", "NEEDS_ADVANCE_APPROVAL", - "NEEDS_PAYMENT_APPROVAL", - "PAYMENT_APPROVED" + "NEEDS_CLOSEOUT", + "CLOSEOUT_COMPLETE" ], "readOnly": true }, @@ -9052,7 +9069,10 @@ func init() { "ZipSITDestHHGFinalAddress", "ZipSITDestHHGOriginalAddress", "ZipSITOriginHHGActualAddress", - "ZipSITOriginHHGOriginalAddress" + "ZipSITOriginHHGOriginalAddress", + "StandaloneCrate", + "StandaloneCrateCap", + "UncappedRequestTotal" ] }, "ServiceItemParamOrigin": { @@ -9490,6 +9510,20 @@ func init() { "x-nullable": true, "x-omitempty": false }, + "actualProGearWeight": { + "description": "The actual weight of any pro gear shipped during a move.", + "type": "integer", + "minimum": 1, + "x-nullable": true, + "example": 4500 + }, + "actualSpouseProGearWeight": { + "description": "The actual weight of any pro gear shipped during a move.", + "type": "integer", + "minimum": 1, + "x-nullable": true, + "example": 4500 + }, "counselorRemarks": { "type": "string", "x-nullable": true, diff --git a/pkg/gen/primemessages/p_p_m_shipment_status.go b/pkg/gen/primemessages/p_p_m_shipment_status.go index 781e529a045..371337b4482 100644 --- a/pkg/gen/primemessages/p_p_m_shipment_status.go +++ b/pkg/gen/primemessages/p_p_m_shipment_status.go @@ -19,8 +19,8 @@ import ( // - **SUBMITTED**: The shipment belongs to a move that has been submitted by the customer or has been created by a Service Counselor or Prime Contractor for a submitted move. // - **WAITING_ON_CUSTOMER**: The PPM shipment has been approved and the customer may now provide their actual move closeout information and documentation required to get paid. // - **NEEDS_ADVANCE_APPROVAL**: The shipment was counseled by the Prime Contractor and approved but an advance was requested so will need further financial approval from the government. -// - **NEEDS_PAYMENT_APPROVAL**: The customer has provided their closeout weight tickets, receipts, and expenses and certified it for the Service Counselor to approve, exclude or reject. -// - **PAYMENT_APPROVED**: The Service Counselor has reviewed all of the customer's PPM closeout documentation and authorizes the customer can download and submit their finalized SSW packet. +// - **NEEDS_CLOSEOUT**: The customer has provided their closeout weight tickets, receipts, and expenses and certified it for the Service Counselor to approve, exclude or reject. +// - **CLOSEOUT_COMPLETE**: The Service Counselor has reviewed all of the customer's PPM closeout documentation and authorizes the customer can download and submit their finalized SSW packet. // // swagger:model PPMShipmentStatus type PPMShipmentStatus string @@ -48,11 +48,11 @@ const ( // PPMShipmentStatusNEEDSADVANCEAPPROVAL captures enum value "NEEDS_ADVANCE_APPROVAL" PPMShipmentStatusNEEDSADVANCEAPPROVAL PPMShipmentStatus = "NEEDS_ADVANCE_APPROVAL" - // PPMShipmentStatusNEEDSPAYMENTAPPROVAL captures enum value "NEEDS_PAYMENT_APPROVAL" - PPMShipmentStatusNEEDSPAYMENTAPPROVAL PPMShipmentStatus = "NEEDS_PAYMENT_APPROVAL" + // PPMShipmentStatusNEEDSCLOSEOUT captures enum value "NEEDS_CLOSEOUT" + PPMShipmentStatusNEEDSCLOSEOUT PPMShipmentStatus = "NEEDS_CLOSEOUT" - // PPMShipmentStatusPAYMENTAPPROVED captures enum value "PAYMENT_APPROVED" - PPMShipmentStatusPAYMENTAPPROVED PPMShipmentStatus = "PAYMENT_APPROVED" + // PPMShipmentStatusCLOSEOUTCOMPLETE captures enum value "CLOSEOUT_COMPLETE" + PPMShipmentStatusCLOSEOUTCOMPLETE PPMShipmentStatus = "CLOSEOUT_COMPLETE" ) // for schema @@ -60,7 +60,7 @@ var pPMShipmentStatusEnum []interface{} func init() { var res []PPMShipmentStatus - if err := json.Unmarshal([]byte(`["DRAFT","SUBMITTED","WAITING_ON_CUSTOMER","NEEDS_ADVANCE_APPROVAL","NEEDS_PAYMENT_APPROVAL","PAYMENT_APPROVED"]`), &res); err != nil { + if err := json.Unmarshal([]byte(`["DRAFT","SUBMITTED","WAITING_ON_CUSTOMER","NEEDS_ADVANCE_APPROVAL","NEEDS_CLOSEOUT","CLOSEOUT_COMPLETE"]`), &res); err != nil { panic(err) } for _, v := range res { diff --git a/pkg/gen/primemessages/service_item_param_name.go b/pkg/gen/primemessages/service_item_param_name.go index e34660eac01..7f8e128b151 100644 --- a/pkg/gen/primemessages/service_item_param_name.go +++ b/pkg/gen/primemessages/service_item_param_name.go @@ -227,6 +227,15 @@ const ( // ServiceItemParamNameZipSITOriginHHGOriginalAddress captures enum value "ZipSITOriginHHGOriginalAddress" ServiceItemParamNameZipSITOriginHHGOriginalAddress ServiceItemParamName = "ZipSITOriginHHGOriginalAddress" + + // ServiceItemParamNameStandaloneCrate captures enum value "StandaloneCrate" + ServiceItemParamNameStandaloneCrate ServiceItemParamName = "StandaloneCrate" + + // ServiceItemParamNameStandaloneCrateCap captures enum value "StandaloneCrateCap" + ServiceItemParamNameStandaloneCrateCap ServiceItemParamName = "StandaloneCrateCap" + + // ServiceItemParamNameUncappedRequestTotal captures enum value "UncappedRequestTotal" + ServiceItemParamNameUncappedRequestTotal ServiceItemParamName = "UncappedRequestTotal" ) // for schema @@ -234,7 +243,7 @@ var serviceItemParamNameEnum []interface{} func init() { var res []ServiceItemParamName - if err := json.Unmarshal([]byte(`["ActualPickupDate","ContractCode","ContractYearName","CubicFeetBilled","CubicFeetCrating","DimensionHeight","DimensionLength","DimensionWidth","DistanceZip","DistanceZipSITDest","DistanceZipSITOrigin","EIAFuelPrice","EscalationCompounded","FSCMultiplier","FSCPriceDifferenceInCents","FSCWeightBasedDistanceMultiplier","IsPeak","MarketDest","MarketOrigin","MTOAvailableToPrimeAt","NTSPackingFactor","NumberDaysSIT","PriceAreaDest","PriceAreaIntlDest","PriceAreaIntlOrigin","PriceAreaOrigin","PriceRateOrFactor","PSI_LinehaulDom","PSI_LinehaulDomPrice","PSI_LinehaulShort","PSI_LinehaulShortPrice","PSI_PriceDomDest","PSI_PriceDomDestPrice","PSI_PriceDomOrigin","PSI_PriceDomOriginPrice","PSI_ShippingLinehaulIntlCO","PSI_ShippingLinehaulIntlCOPrice","PSI_ShippingLinehaulIntlOC","PSI_ShippingLinehaulIntlOCPrice","PSI_ShippingLinehaulIntlOO","PSI_ShippingLinehaulIntlOOPrice","RateAreaNonStdDest","RateAreaNonStdOrigin","ReferenceDate","RequestedPickupDate","ServiceAreaDest","ServiceAreaOrigin","ServicesScheduleDest","ServicesScheduleOrigin","SITPaymentRequestEnd","SITPaymentRequestStart","SITScheduleDest","SITScheduleOrigin","SITServiceAreaDest","SITServiceAreaOrigin","WeightAdjusted","WeightBilled","WeightEstimated","WeightOriginal","WeightReweigh","ZipDestAddress","ZipPickupAddress","ZipSITDestHHGFinalAddress","ZipSITDestHHGOriginalAddress","ZipSITOriginHHGActualAddress","ZipSITOriginHHGOriginalAddress"]`), &res); err != nil { + if err := json.Unmarshal([]byte(`["ActualPickupDate","ContractCode","ContractYearName","CubicFeetBilled","CubicFeetCrating","DimensionHeight","DimensionLength","DimensionWidth","DistanceZip","DistanceZipSITDest","DistanceZipSITOrigin","EIAFuelPrice","EscalationCompounded","FSCMultiplier","FSCPriceDifferenceInCents","FSCWeightBasedDistanceMultiplier","IsPeak","MarketDest","MarketOrigin","MTOAvailableToPrimeAt","NTSPackingFactor","NumberDaysSIT","PriceAreaDest","PriceAreaIntlDest","PriceAreaIntlOrigin","PriceAreaOrigin","PriceRateOrFactor","PSI_LinehaulDom","PSI_LinehaulDomPrice","PSI_LinehaulShort","PSI_LinehaulShortPrice","PSI_PriceDomDest","PSI_PriceDomDestPrice","PSI_PriceDomOrigin","PSI_PriceDomOriginPrice","PSI_ShippingLinehaulIntlCO","PSI_ShippingLinehaulIntlCOPrice","PSI_ShippingLinehaulIntlOC","PSI_ShippingLinehaulIntlOCPrice","PSI_ShippingLinehaulIntlOO","PSI_ShippingLinehaulIntlOOPrice","RateAreaNonStdDest","RateAreaNonStdOrigin","ReferenceDate","RequestedPickupDate","ServiceAreaDest","ServiceAreaOrigin","ServicesScheduleDest","ServicesScheduleOrigin","SITPaymentRequestEnd","SITPaymentRequestStart","SITScheduleDest","SITScheduleOrigin","SITServiceAreaDest","SITServiceAreaOrigin","WeightAdjusted","WeightBilled","WeightEstimated","WeightOriginal","WeightReweigh","ZipDestAddress","ZipPickupAddress","ZipSITDestHHGFinalAddress","ZipSITDestHHGOriginalAddress","ZipSITOriginHHGActualAddress","ZipSITOriginHHGOriginalAddress","StandaloneCrate","StandaloneCrateCap","UncappedRequestTotal"]`), &res); err != nil { panic(err) } for _, v := range res { diff --git a/pkg/gen/primemessages/update_m_t_o_shipment.go b/pkg/gen/primemessages/update_m_t_o_shipment.go index 1275ad14a1b..074e9772850 100644 --- a/pkg/gen/primemessages/update_m_t_o_shipment.go +++ b/pkg/gen/primemessages/update_m_t_o_shipment.go @@ -27,6 +27,16 @@ type UpdateMTOShipment struct { // Format: date ActualPickupDate *strfmt.Date `json:"actualPickupDate"` + // The actual weight of any pro gear shipped during a move. + // Example: 4500 + // Minimum: 1 + ActualProGearWeight *int64 `json:"actualProGearWeight,omitempty"` + + // The actual weight of any pro gear shipped during a move. + // Example: 4500 + // Minimum: 1 + ActualSpouseProGearWeight *int64 `json:"actualSpouseProGearWeight,omitempty"` + // counselor remarks // Example: counselor approved CounselorRemarks *string `json:"counselorRemarks,omitempty"` @@ -118,6 +128,14 @@ func (m *UpdateMTOShipment) Validate(formats strfmt.Registry) error { res = append(res, err) } + if err := m.validateActualProGearWeight(formats); err != nil { + res = append(res, err) + } + + if err := m.validateActualSpouseProGearWeight(formats); err != nil { + res = append(res, err) + } + if err := m.validateDestinationAddress(formats); err != nil { res = append(res, err) } @@ -200,6 +218,30 @@ func (m *UpdateMTOShipment) validateActualPickupDate(formats strfmt.Registry) er return nil } +func (m *UpdateMTOShipment) validateActualProGearWeight(formats strfmt.Registry) error { + if swag.IsZero(m.ActualProGearWeight) { // not required + return nil + } + + if err := validate.MinimumInt("actualProGearWeight", "body", *m.ActualProGearWeight, 1, false); err != nil { + return err + } + + return nil +} + +func (m *UpdateMTOShipment) validateActualSpouseProGearWeight(formats strfmt.Registry) error { + if swag.IsZero(m.ActualSpouseProGearWeight) { // not required + return nil + } + + if err := validate.MinimumInt("actualSpouseProGearWeight", "body", *m.ActualSpouseProGearWeight, 1, false); err != nil { + return err + } + + return nil +} + func (m *UpdateMTOShipment) validateDestinationAddress(formats strfmt.Registry) error { if swag.IsZero(m.DestinationAddress) { // not required return nil diff --git a/pkg/gen/primev2api/embedded_spec.go b/pkg/gen/primev2api/embedded_spec.go index f078f4a05c5..f48044499f7 100644 --- a/pkg/gen/primev2api/embedded_spec.go +++ b/pkg/gen/primev2api/embedded_spec.go @@ -2157,15 +2157,15 @@ func init() { "x-nullable": true }, "PPMShipmentStatus": { - "description": "Status of the PPM Shipment:\n * **DRAFT**: The customer has created the PPM shipment but has not yet submitted their move for counseling.\n * **SUBMITTED**: The shipment belongs to a move that has been submitted by the customer or has been created by a Service Counselor or Prime Contractor for a submitted move.\n * **WAITING_ON_CUSTOMER**: The PPM shipment has been approved and the customer may now provide their actual move closeout information and documentation required to get paid.\n * **NEEDS_ADVANCE_APPROVAL**: The shipment was counseled by the Prime Contractor and approved but an advance was requested so will need further financial approval from the government.\n * **NEEDS_PAYMENT_APPROVAL**: The customer has provided their closeout weight tickets, receipts, and expenses and certified it for the Service Counselor to approve, exclude or reject.\n * **PAYMENT_APPROVED**: The Service Counselor has reviewed all of the customer's PPM closeout documentation and authorizes the customer can download and submit their finalized SSW packet.\n", + "description": "Status of the PPM Shipment:\n * **DRAFT**: The customer has created the PPM shipment but has not yet submitted their move for counseling.\n * **SUBMITTED**: The shipment belongs to a move that has been submitted by the customer or has been created by a Service Counselor or Prime Contractor for a submitted move.\n * **WAITING_ON_CUSTOMER**: The PPM shipment has been approved and the customer may now provide their actual move closeout information and documentation required to get paid.\n * **NEEDS_ADVANCE_APPROVAL**: The shipment was counseled by the Prime Contractor and approved but an advance was requested so will need further financial approval from the government.\n * **NEEDS_CLOSEOUT**: The customer has provided their closeout weight tickets, receipts, and expenses and certified it for the Service Counselor to approve, exclude or reject.\n * **CLOSEOUT_COMPLETE**: The Service Counselor has reviewed all of the customer's PPM closeout documentation and authorizes the customer can download and submit their finalized SSW packet.\n", "type": "string", "enum": [ "DRAFT", "SUBMITTED", "WAITING_ON_CUSTOMER", "NEEDS_ADVANCE_APPROVAL", - "NEEDS_PAYMENT_APPROVAL", - "PAYMENT_APPROVED" + "NEEDS_CLOSEOUT", + "CLOSEOUT_COMPLETE" ], "readOnly": true }, @@ -2637,7 +2637,10 @@ func init() { "ZipSITDestHHGFinalAddress", "ZipSITDestHHGOriginalAddress", "ZipSITOriginHHGActualAddress", - "ZipSITOriginHHGOriginalAddress" + "ZipSITOriginHHGOriginalAddress", + "StandaloneCrate", + "StandaloneCrateCap", + "UncappedRequestTotal" ] }, "ServiceItemParamOrigin": { @@ -5661,15 +5664,15 @@ func init() { "x-nullable": true }, "PPMShipmentStatus": { - "description": "Status of the PPM Shipment:\n * **DRAFT**: The customer has created the PPM shipment but has not yet submitted their move for counseling.\n * **SUBMITTED**: The shipment belongs to a move that has been submitted by the customer or has been created by a Service Counselor or Prime Contractor for a submitted move.\n * **WAITING_ON_CUSTOMER**: The PPM shipment has been approved and the customer may now provide their actual move closeout information and documentation required to get paid.\n * **NEEDS_ADVANCE_APPROVAL**: The shipment was counseled by the Prime Contractor and approved but an advance was requested so will need further financial approval from the government.\n * **NEEDS_PAYMENT_APPROVAL**: The customer has provided their closeout weight tickets, receipts, and expenses and certified it for the Service Counselor to approve, exclude or reject.\n * **PAYMENT_APPROVED**: The Service Counselor has reviewed all of the customer's PPM closeout documentation and authorizes the customer can download and submit their finalized SSW packet.\n", + "description": "Status of the PPM Shipment:\n * **DRAFT**: The customer has created the PPM shipment but has not yet submitted their move for counseling.\n * **SUBMITTED**: The shipment belongs to a move that has been submitted by the customer or has been created by a Service Counselor or Prime Contractor for a submitted move.\n * **WAITING_ON_CUSTOMER**: The PPM shipment has been approved and the customer may now provide their actual move closeout information and documentation required to get paid.\n * **NEEDS_ADVANCE_APPROVAL**: The shipment was counseled by the Prime Contractor and approved but an advance was requested so will need further financial approval from the government.\n * **NEEDS_CLOSEOUT**: The customer has provided their closeout weight tickets, receipts, and expenses and certified it for the Service Counselor to approve, exclude or reject.\n * **CLOSEOUT_COMPLETE**: The Service Counselor has reviewed all of the customer's PPM closeout documentation and authorizes the customer can download and submit their finalized SSW packet.\n", "type": "string", "enum": [ "DRAFT", "SUBMITTED", "WAITING_ON_CUSTOMER", "NEEDS_ADVANCE_APPROVAL", - "NEEDS_PAYMENT_APPROVAL", - "PAYMENT_APPROVED" + "NEEDS_CLOSEOUT", + "CLOSEOUT_COMPLETE" ], "readOnly": true }, @@ -6141,7 +6144,10 @@ func init() { "ZipSITDestHHGFinalAddress", "ZipSITDestHHGOriginalAddress", "ZipSITOriginHHGActualAddress", - "ZipSITOriginHHGOriginalAddress" + "ZipSITOriginHHGOriginalAddress", + "StandaloneCrate", + "StandaloneCrateCap", + "UncappedRequestTotal" ] }, "ServiceItemParamOrigin": { diff --git a/pkg/gen/primev2messages/p_p_m_shipment_status.go b/pkg/gen/primev2messages/p_p_m_shipment_status.go index 72ecfe774bc..439086abcaa 100644 --- a/pkg/gen/primev2messages/p_p_m_shipment_status.go +++ b/pkg/gen/primev2messages/p_p_m_shipment_status.go @@ -19,8 +19,8 @@ import ( // - **SUBMITTED**: The shipment belongs to a move that has been submitted by the customer or has been created by a Service Counselor or Prime Contractor for a submitted move. // - **WAITING_ON_CUSTOMER**: The PPM shipment has been approved and the customer may now provide their actual move closeout information and documentation required to get paid. // - **NEEDS_ADVANCE_APPROVAL**: The shipment was counseled by the Prime Contractor and approved but an advance was requested so will need further financial approval from the government. -// - **NEEDS_PAYMENT_APPROVAL**: The customer has provided their closeout weight tickets, receipts, and expenses and certified it for the Service Counselor to approve, exclude or reject. -// - **PAYMENT_APPROVED**: The Service Counselor has reviewed all of the customer's PPM closeout documentation and authorizes the customer can download and submit their finalized SSW packet. +// - **NEEDS_CLOSEOUT**: The customer has provided their closeout weight tickets, receipts, and expenses and certified it for the Service Counselor to approve, exclude or reject. +// - **CLOSEOUT_COMPLETE**: The Service Counselor has reviewed all of the customer's PPM closeout documentation and authorizes the customer can download and submit their finalized SSW packet. // // swagger:model PPMShipmentStatus type PPMShipmentStatus string @@ -48,11 +48,11 @@ const ( // PPMShipmentStatusNEEDSADVANCEAPPROVAL captures enum value "NEEDS_ADVANCE_APPROVAL" PPMShipmentStatusNEEDSADVANCEAPPROVAL PPMShipmentStatus = "NEEDS_ADVANCE_APPROVAL" - // PPMShipmentStatusNEEDSPAYMENTAPPROVAL captures enum value "NEEDS_PAYMENT_APPROVAL" - PPMShipmentStatusNEEDSPAYMENTAPPROVAL PPMShipmentStatus = "NEEDS_PAYMENT_APPROVAL" + // PPMShipmentStatusNEEDSCLOSEOUT captures enum value "NEEDS_CLOSEOUT" + PPMShipmentStatusNEEDSCLOSEOUT PPMShipmentStatus = "NEEDS_CLOSEOUT" - // PPMShipmentStatusPAYMENTAPPROVED captures enum value "PAYMENT_APPROVED" - PPMShipmentStatusPAYMENTAPPROVED PPMShipmentStatus = "PAYMENT_APPROVED" + // PPMShipmentStatusCLOSEOUTCOMPLETE captures enum value "CLOSEOUT_COMPLETE" + PPMShipmentStatusCLOSEOUTCOMPLETE PPMShipmentStatus = "CLOSEOUT_COMPLETE" ) // for schema @@ -60,7 +60,7 @@ var pPMShipmentStatusEnum []interface{} func init() { var res []PPMShipmentStatus - if err := json.Unmarshal([]byte(`["DRAFT","SUBMITTED","WAITING_ON_CUSTOMER","NEEDS_ADVANCE_APPROVAL","NEEDS_PAYMENT_APPROVAL","PAYMENT_APPROVED"]`), &res); err != nil { + if err := json.Unmarshal([]byte(`["DRAFT","SUBMITTED","WAITING_ON_CUSTOMER","NEEDS_ADVANCE_APPROVAL","NEEDS_CLOSEOUT","CLOSEOUT_COMPLETE"]`), &res); err != nil { panic(err) } for _, v := range res { diff --git a/pkg/gen/primev2messages/service_item_param_name.go b/pkg/gen/primev2messages/service_item_param_name.go index 330e1fc59e4..a6939ad00f4 100644 --- a/pkg/gen/primev2messages/service_item_param_name.go +++ b/pkg/gen/primev2messages/service_item_param_name.go @@ -227,6 +227,15 @@ const ( // ServiceItemParamNameZipSITOriginHHGOriginalAddress captures enum value "ZipSITOriginHHGOriginalAddress" ServiceItemParamNameZipSITOriginHHGOriginalAddress ServiceItemParamName = "ZipSITOriginHHGOriginalAddress" + + // ServiceItemParamNameStandaloneCrate captures enum value "StandaloneCrate" + ServiceItemParamNameStandaloneCrate ServiceItemParamName = "StandaloneCrate" + + // ServiceItemParamNameStandaloneCrateCap captures enum value "StandaloneCrateCap" + ServiceItemParamNameStandaloneCrateCap ServiceItemParamName = "StandaloneCrateCap" + + // ServiceItemParamNameUncappedRequestTotal captures enum value "UncappedRequestTotal" + ServiceItemParamNameUncappedRequestTotal ServiceItemParamName = "UncappedRequestTotal" ) // for schema @@ -234,7 +243,7 @@ var serviceItemParamNameEnum []interface{} func init() { var res []ServiceItemParamName - if err := json.Unmarshal([]byte(`["ActualPickupDate","ContractCode","ContractYearName","CubicFeetBilled","CubicFeetCrating","DimensionHeight","DimensionLength","DimensionWidth","DistanceZip","DistanceZipSITDest","DistanceZipSITOrigin","EIAFuelPrice","EscalationCompounded","FSCMultiplier","FSCPriceDifferenceInCents","FSCWeightBasedDistanceMultiplier","IsPeak","MarketDest","MarketOrigin","MTOAvailableToPrimeAt","NTSPackingFactor","NumberDaysSIT","PriceAreaDest","PriceAreaIntlDest","PriceAreaIntlOrigin","PriceAreaOrigin","PriceRateOrFactor","PSI_LinehaulDom","PSI_LinehaulDomPrice","PSI_LinehaulShort","PSI_LinehaulShortPrice","PSI_PriceDomDest","PSI_PriceDomDestPrice","PSI_PriceDomOrigin","PSI_PriceDomOriginPrice","PSI_ShippingLinehaulIntlCO","PSI_ShippingLinehaulIntlCOPrice","PSI_ShippingLinehaulIntlOC","PSI_ShippingLinehaulIntlOCPrice","PSI_ShippingLinehaulIntlOO","PSI_ShippingLinehaulIntlOOPrice","RateAreaNonStdDest","RateAreaNonStdOrigin","ReferenceDate","RequestedPickupDate","ServiceAreaDest","ServiceAreaOrigin","ServicesScheduleDest","ServicesScheduleOrigin","SITPaymentRequestEnd","SITPaymentRequestStart","SITScheduleDest","SITScheduleOrigin","SITServiceAreaDest","SITServiceAreaOrigin","WeightAdjusted","WeightBilled","WeightEstimated","WeightOriginal","WeightReweigh","ZipDestAddress","ZipPickupAddress","ZipSITDestHHGFinalAddress","ZipSITDestHHGOriginalAddress","ZipSITOriginHHGActualAddress","ZipSITOriginHHGOriginalAddress"]`), &res); err != nil { + if err := json.Unmarshal([]byte(`["ActualPickupDate","ContractCode","ContractYearName","CubicFeetBilled","CubicFeetCrating","DimensionHeight","DimensionLength","DimensionWidth","DistanceZip","DistanceZipSITDest","DistanceZipSITOrigin","EIAFuelPrice","EscalationCompounded","FSCMultiplier","FSCPriceDifferenceInCents","FSCWeightBasedDistanceMultiplier","IsPeak","MarketDest","MarketOrigin","MTOAvailableToPrimeAt","NTSPackingFactor","NumberDaysSIT","PriceAreaDest","PriceAreaIntlDest","PriceAreaIntlOrigin","PriceAreaOrigin","PriceRateOrFactor","PSI_LinehaulDom","PSI_LinehaulDomPrice","PSI_LinehaulShort","PSI_LinehaulShortPrice","PSI_PriceDomDest","PSI_PriceDomDestPrice","PSI_PriceDomOrigin","PSI_PriceDomOriginPrice","PSI_ShippingLinehaulIntlCO","PSI_ShippingLinehaulIntlCOPrice","PSI_ShippingLinehaulIntlOC","PSI_ShippingLinehaulIntlOCPrice","PSI_ShippingLinehaulIntlOO","PSI_ShippingLinehaulIntlOOPrice","RateAreaNonStdDest","RateAreaNonStdOrigin","ReferenceDate","RequestedPickupDate","ServiceAreaDest","ServiceAreaOrigin","ServicesScheduleDest","ServicesScheduleOrigin","SITPaymentRequestEnd","SITPaymentRequestStart","SITScheduleDest","SITScheduleOrigin","SITServiceAreaDest","SITServiceAreaOrigin","WeightAdjusted","WeightBilled","WeightEstimated","WeightOriginal","WeightReweigh","ZipDestAddress","ZipPickupAddress","ZipSITDestHHGFinalAddress","ZipSITDestHHGOriginalAddress","ZipSITOriginHHGActualAddress","ZipSITOriginHHGOriginalAddress","StandaloneCrate","StandaloneCrateCap","UncappedRequestTotal"]`), &res); err != nil { panic(err) } for _, v := range res { diff --git a/pkg/gen/primev3api/embedded_spec.go b/pkg/gen/primev3api/embedded_spec.go index b0781334cd5..7a500cbaf13 100644 --- a/pkg/gen/primev3api/embedded_spec.go +++ b/pkg/gen/primev3api/embedded_spec.go @@ -2137,15 +2137,15 @@ func init() { "x-nullable": true }, "PPMShipmentStatus": { - "description": "Status of the PPM Shipment:\n * **DRAFT**: The customer has created the PPM shipment but has not yet submitted their move for counseling.\n * **SUBMITTED**: The shipment belongs to a move that has been submitted by the customer or has been created by a Service Counselor or Prime Contractor for a submitted move.\n * **WAITING_ON_CUSTOMER**: The PPM shipment has been approved and the customer may now provide their actual move closeout information and documentation required to get paid.\n * **NEEDS_ADVANCE_APPROVAL**: The shipment was counseled by the Prime Contractor and approved but an advance was requested so will need further financial approval from the government.\n * **NEEDS_PAYMENT_APPROVAL**: The customer has provided their closeout weight tickets, receipts, and expenses and certified it for the Service Counselor to approve, exclude or reject.\n * **PAYMENT_APPROVED**: The Service Counselor has reviewed all of the customer's PPM closeout documentation and authorizes the customer can download and submit their finalized SSW packet.\n", + "description": "Status of the PPM Shipment:\n * **DRAFT**: The customer has created the PPM shipment but has not yet submitted their move for counseling.\n * **SUBMITTED**: The shipment belongs to a move that has been submitted by the customer or has been created by a Service Counselor or Prime Contractor for a submitted move.\n * **WAITING_ON_CUSTOMER**: The PPM shipment has been approved and the customer may now provide their actual move closeout information and documentation required to get paid.\n * **NEEDS_ADVANCE_APPROVAL**: The shipment was counseled by the Prime Contractor and approved but an advance was requested so will need further financial approval from the government.\n * **NEEDS_CLOSEOUT**: The customer has provided their closeout weight tickets, receipts, and expenses and certified it for the Service Counselor to approve, exclude or reject.\n * **CLOSEOUT_COMPLETE**: The Service Counselor has reviewed all of the customer's PPM closeout documentation and authorizes the customer can download and submit their finalized SSW packet.\n", "type": "string", "enum": [ "DRAFT", "SUBMITTED", "WAITING_ON_CUSTOMER", "NEEDS_ADVANCE_APPROVAL", - "NEEDS_PAYMENT_APPROVAL", - "PAYMENT_APPROVED" + "NEEDS_CLOSEOUT", + "CLOSEOUT_COMPLETE" ], "readOnly": true }, @@ -2617,7 +2617,10 @@ func init() { "ZipSITDestHHGFinalAddress", "ZipSITDestHHGOriginalAddress", "ZipSITOriginHHGActualAddress", - "ZipSITOriginHHGOriginalAddress" + "ZipSITOriginHHGOriginalAddress", + "StandaloneCrate", + "StandaloneCrateCap", + "UncappedRequestTotal" ] }, "ServiceItemParamOrigin": { @@ -3039,6 +3042,18 @@ func init() { "x-nullable": true, "x-omitempty": false }, + "actualProGearWeight": { + "description": "The actual weight of any pro gear shipped during a move.", + "type": "integer", + "x-nullable": true, + "example": 4500 + }, + "actualSpouseProGearWeight": { + "description": "The actual weight of any pro gear shipped during a move.", + "type": "integer", + "x-nullable": true, + "example": 4500 + }, "counselorRemarks": { "type": "string", "x-nullable": true, @@ -5620,15 +5635,15 @@ func init() { "x-nullable": true }, "PPMShipmentStatus": { - "description": "Status of the PPM Shipment:\n * **DRAFT**: The customer has created the PPM shipment but has not yet submitted their move for counseling.\n * **SUBMITTED**: The shipment belongs to a move that has been submitted by the customer or has been created by a Service Counselor or Prime Contractor for a submitted move.\n * **WAITING_ON_CUSTOMER**: The PPM shipment has been approved and the customer may now provide their actual move closeout information and documentation required to get paid.\n * **NEEDS_ADVANCE_APPROVAL**: The shipment was counseled by the Prime Contractor and approved but an advance was requested so will need further financial approval from the government.\n * **NEEDS_PAYMENT_APPROVAL**: The customer has provided their closeout weight tickets, receipts, and expenses and certified it for the Service Counselor to approve, exclude or reject.\n * **PAYMENT_APPROVED**: The Service Counselor has reviewed all of the customer's PPM closeout documentation and authorizes the customer can download and submit their finalized SSW packet.\n", + "description": "Status of the PPM Shipment:\n * **DRAFT**: The customer has created the PPM shipment but has not yet submitted their move for counseling.\n * **SUBMITTED**: The shipment belongs to a move that has been submitted by the customer or has been created by a Service Counselor or Prime Contractor for a submitted move.\n * **WAITING_ON_CUSTOMER**: The PPM shipment has been approved and the customer may now provide their actual move closeout information and documentation required to get paid.\n * **NEEDS_ADVANCE_APPROVAL**: The shipment was counseled by the Prime Contractor and approved but an advance was requested so will need further financial approval from the government.\n * **NEEDS_CLOSEOUT**: The customer has provided their closeout weight tickets, receipts, and expenses and certified it for the Service Counselor to approve, exclude or reject.\n * **CLOSEOUT_COMPLETE**: The Service Counselor has reviewed all of the customer's PPM closeout documentation and authorizes the customer can download and submit their finalized SSW packet.\n", "type": "string", "enum": [ "DRAFT", "SUBMITTED", "WAITING_ON_CUSTOMER", "NEEDS_ADVANCE_APPROVAL", - "NEEDS_PAYMENT_APPROVAL", - "PAYMENT_APPROVED" + "NEEDS_CLOSEOUT", + "CLOSEOUT_COMPLETE" ], "readOnly": true }, @@ -6100,7 +6115,10 @@ func init() { "ZipSITDestHHGFinalAddress", "ZipSITDestHHGOriginalAddress", "ZipSITOriginHHGActualAddress", - "ZipSITOriginHHGOriginalAddress" + "ZipSITOriginHHGOriginalAddress", + "StandaloneCrate", + "StandaloneCrateCap", + "UncappedRequestTotal" ] }, "ServiceItemParamOrigin": { @@ -6524,6 +6542,18 @@ func init() { "x-nullable": true, "x-omitempty": false }, + "actualProGearWeight": { + "description": "The actual weight of any pro gear shipped during a move.", + "type": "integer", + "x-nullable": true, + "example": 4500 + }, + "actualSpouseProGearWeight": { + "description": "The actual weight of any pro gear shipped during a move.", + "type": "integer", + "x-nullable": true, + "example": 4500 + }, "counselorRemarks": { "type": "string", "x-nullable": true, diff --git a/pkg/gen/primev3messages/p_p_m_shipment_status.go b/pkg/gen/primev3messages/p_p_m_shipment_status.go index 63dd693bf77..e594db1bc55 100644 --- a/pkg/gen/primev3messages/p_p_m_shipment_status.go +++ b/pkg/gen/primev3messages/p_p_m_shipment_status.go @@ -19,8 +19,8 @@ import ( // - **SUBMITTED**: The shipment belongs to a move that has been submitted by the customer or has been created by a Service Counselor or Prime Contractor for a submitted move. // - **WAITING_ON_CUSTOMER**: The PPM shipment has been approved and the customer may now provide their actual move closeout information and documentation required to get paid. // - **NEEDS_ADVANCE_APPROVAL**: The shipment was counseled by the Prime Contractor and approved but an advance was requested so will need further financial approval from the government. -// - **NEEDS_PAYMENT_APPROVAL**: The customer has provided their closeout weight tickets, receipts, and expenses and certified it for the Service Counselor to approve, exclude or reject. -// - **PAYMENT_APPROVED**: The Service Counselor has reviewed all of the customer's PPM closeout documentation and authorizes the customer can download and submit their finalized SSW packet. +// - **NEEDS_CLOSEOUT**: The customer has provided their closeout weight tickets, receipts, and expenses and certified it for the Service Counselor to approve, exclude or reject. +// - **CLOSEOUT_COMPLETE**: The Service Counselor has reviewed all of the customer's PPM closeout documentation and authorizes the customer can download and submit their finalized SSW packet. // // swagger:model PPMShipmentStatus type PPMShipmentStatus string @@ -48,11 +48,11 @@ const ( // PPMShipmentStatusNEEDSADVANCEAPPROVAL captures enum value "NEEDS_ADVANCE_APPROVAL" PPMShipmentStatusNEEDSADVANCEAPPROVAL PPMShipmentStatus = "NEEDS_ADVANCE_APPROVAL" - // PPMShipmentStatusNEEDSPAYMENTAPPROVAL captures enum value "NEEDS_PAYMENT_APPROVAL" - PPMShipmentStatusNEEDSPAYMENTAPPROVAL PPMShipmentStatus = "NEEDS_PAYMENT_APPROVAL" + // PPMShipmentStatusNEEDSCLOSEOUT captures enum value "NEEDS_CLOSEOUT" + PPMShipmentStatusNEEDSCLOSEOUT PPMShipmentStatus = "NEEDS_CLOSEOUT" - // PPMShipmentStatusPAYMENTAPPROVED captures enum value "PAYMENT_APPROVED" - PPMShipmentStatusPAYMENTAPPROVED PPMShipmentStatus = "PAYMENT_APPROVED" + // PPMShipmentStatusCLOSEOUTCOMPLETE captures enum value "CLOSEOUT_COMPLETE" + PPMShipmentStatusCLOSEOUTCOMPLETE PPMShipmentStatus = "CLOSEOUT_COMPLETE" ) // for schema @@ -60,7 +60,7 @@ var pPMShipmentStatusEnum []interface{} func init() { var res []PPMShipmentStatus - if err := json.Unmarshal([]byte(`["DRAFT","SUBMITTED","WAITING_ON_CUSTOMER","NEEDS_ADVANCE_APPROVAL","NEEDS_PAYMENT_APPROVAL","PAYMENT_APPROVED"]`), &res); err != nil { + if err := json.Unmarshal([]byte(`["DRAFT","SUBMITTED","WAITING_ON_CUSTOMER","NEEDS_ADVANCE_APPROVAL","NEEDS_CLOSEOUT","CLOSEOUT_COMPLETE"]`), &res); err != nil { panic(err) } for _, v := range res { diff --git a/pkg/gen/primev3messages/service_item_param_name.go b/pkg/gen/primev3messages/service_item_param_name.go index 51a6f63beea..ab53b71f111 100644 --- a/pkg/gen/primev3messages/service_item_param_name.go +++ b/pkg/gen/primev3messages/service_item_param_name.go @@ -227,6 +227,15 @@ const ( // ServiceItemParamNameZipSITOriginHHGOriginalAddress captures enum value "ZipSITOriginHHGOriginalAddress" ServiceItemParamNameZipSITOriginHHGOriginalAddress ServiceItemParamName = "ZipSITOriginHHGOriginalAddress" + + // ServiceItemParamNameStandaloneCrate captures enum value "StandaloneCrate" + ServiceItemParamNameStandaloneCrate ServiceItemParamName = "StandaloneCrate" + + // ServiceItemParamNameStandaloneCrateCap captures enum value "StandaloneCrateCap" + ServiceItemParamNameStandaloneCrateCap ServiceItemParamName = "StandaloneCrateCap" + + // ServiceItemParamNameUncappedRequestTotal captures enum value "UncappedRequestTotal" + ServiceItemParamNameUncappedRequestTotal ServiceItemParamName = "UncappedRequestTotal" ) // for schema @@ -234,7 +243,7 @@ var serviceItemParamNameEnum []interface{} func init() { var res []ServiceItemParamName - if err := json.Unmarshal([]byte(`["ActualPickupDate","ContractCode","ContractYearName","CubicFeetBilled","CubicFeetCrating","DimensionHeight","DimensionLength","DimensionWidth","DistanceZip","DistanceZipSITDest","DistanceZipSITOrigin","EIAFuelPrice","EscalationCompounded","FSCMultiplier","FSCPriceDifferenceInCents","FSCWeightBasedDistanceMultiplier","IsPeak","MarketDest","MarketOrigin","MTOAvailableToPrimeAt","NTSPackingFactor","NumberDaysSIT","PriceAreaDest","PriceAreaIntlDest","PriceAreaIntlOrigin","PriceAreaOrigin","PriceRateOrFactor","PSI_LinehaulDom","PSI_LinehaulDomPrice","PSI_LinehaulShort","PSI_LinehaulShortPrice","PSI_PriceDomDest","PSI_PriceDomDestPrice","PSI_PriceDomOrigin","PSI_PriceDomOriginPrice","PSI_ShippingLinehaulIntlCO","PSI_ShippingLinehaulIntlCOPrice","PSI_ShippingLinehaulIntlOC","PSI_ShippingLinehaulIntlOCPrice","PSI_ShippingLinehaulIntlOO","PSI_ShippingLinehaulIntlOOPrice","RateAreaNonStdDest","RateAreaNonStdOrigin","ReferenceDate","RequestedPickupDate","ServiceAreaDest","ServiceAreaOrigin","ServicesScheduleDest","ServicesScheduleOrigin","SITPaymentRequestEnd","SITPaymentRequestStart","SITScheduleDest","SITScheduleOrigin","SITServiceAreaDest","SITServiceAreaOrigin","WeightAdjusted","WeightBilled","WeightEstimated","WeightOriginal","WeightReweigh","ZipDestAddress","ZipPickupAddress","ZipSITDestHHGFinalAddress","ZipSITDestHHGOriginalAddress","ZipSITOriginHHGActualAddress","ZipSITOriginHHGOriginalAddress"]`), &res); err != nil { + if err := json.Unmarshal([]byte(`["ActualPickupDate","ContractCode","ContractYearName","CubicFeetBilled","CubicFeetCrating","DimensionHeight","DimensionLength","DimensionWidth","DistanceZip","DistanceZipSITDest","DistanceZipSITOrigin","EIAFuelPrice","EscalationCompounded","FSCMultiplier","FSCPriceDifferenceInCents","FSCWeightBasedDistanceMultiplier","IsPeak","MarketDest","MarketOrigin","MTOAvailableToPrimeAt","NTSPackingFactor","NumberDaysSIT","PriceAreaDest","PriceAreaIntlDest","PriceAreaIntlOrigin","PriceAreaOrigin","PriceRateOrFactor","PSI_LinehaulDom","PSI_LinehaulDomPrice","PSI_LinehaulShort","PSI_LinehaulShortPrice","PSI_PriceDomDest","PSI_PriceDomDestPrice","PSI_PriceDomOrigin","PSI_PriceDomOriginPrice","PSI_ShippingLinehaulIntlCO","PSI_ShippingLinehaulIntlCOPrice","PSI_ShippingLinehaulIntlOC","PSI_ShippingLinehaulIntlOCPrice","PSI_ShippingLinehaulIntlOO","PSI_ShippingLinehaulIntlOOPrice","RateAreaNonStdDest","RateAreaNonStdOrigin","ReferenceDate","RequestedPickupDate","ServiceAreaDest","ServiceAreaOrigin","ServicesScheduleDest","ServicesScheduleOrigin","SITPaymentRequestEnd","SITPaymentRequestStart","SITScheduleDest","SITScheduleOrigin","SITServiceAreaDest","SITServiceAreaOrigin","WeightAdjusted","WeightBilled","WeightEstimated","WeightOriginal","WeightReweigh","ZipDestAddress","ZipPickupAddress","ZipSITDestHHGFinalAddress","ZipSITDestHHGOriginalAddress","ZipSITOriginHHGActualAddress","ZipSITOriginHHGOriginalAddress","StandaloneCrate","StandaloneCrateCap","UncappedRequestTotal"]`), &res); err != nil { panic(err) } for _, v := range res { diff --git a/pkg/gen/primev3messages/update_m_t_o_shipment.go b/pkg/gen/primev3messages/update_m_t_o_shipment.go index 9ac3991ac02..037dbf4557f 100644 --- a/pkg/gen/primev3messages/update_m_t_o_shipment.go +++ b/pkg/gen/primev3messages/update_m_t_o_shipment.go @@ -27,6 +27,14 @@ type UpdateMTOShipment struct { // Format: date ActualPickupDate *strfmt.Date `json:"actualPickupDate"` + // The actual weight of any pro gear shipped during a move. + // Example: 4500 + ActualProGearWeight *int64 `json:"actualProGearWeight,omitempty"` + + // The actual weight of any pro gear shipped during a move. + // Example: 4500 + ActualSpouseProGearWeight *int64 `json:"actualSpouseProGearWeight,omitempty"` + // counselor remarks // Example: counselor approved CounselorRemarks *string `json:"counselorRemarks,omitempty"` diff --git a/pkg/handlers/adminapi/api.go b/pkg/handlers/adminapi/api.go index 9d61506061e..02b3c0e677e 100644 --- a/pkg/handlers/adminapi/api.go +++ b/pkg/handlers/adminapi/api.go @@ -12,6 +12,7 @@ import ( "github.com/transcom/mymove/pkg/services/clientcert" electronicorder "github.com/transcom/mymove/pkg/services/electronic_order" fetch "github.com/transcom/mymove/pkg/services/fetch" + "github.com/transcom/mymove/pkg/services/ghcrateengine" move "github.com/transcom/mymove/pkg/services/move" movetaskorder "github.com/transcom/mymove/pkg/services/move_task_order" mtoserviceitem "github.com/transcom/mymove/pkg/services/mto_service_item" @@ -196,7 +197,7 @@ func NewAdminAPI(handlerConfig handlers.HandlerConfig) *adminops.MymoveAPI { handlerConfig, movetaskorder.NewMoveTaskOrderUpdater( queryBuilder, - mtoserviceitem.NewMTOServiceItemCreator(handlerConfig.HHGPlanner(), queryBuilder, moveRouter), + mtoserviceitem.NewMTOServiceItemCreator(handlerConfig.HHGPlanner(), queryBuilder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), moveRouter, ), } diff --git a/pkg/handlers/adminapi/moves_test.go b/pkg/handlers/adminapi/moves_test.go index dba92cc2b3e..c078bf71b33 100644 --- a/pkg/handlers/adminapi/moves_test.go +++ b/pkg/handlers/adminapi/moves_test.go @@ -15,6 +15,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/ghcrateengine" "github.com/transcom/mymove/pkg/services/mocks" "github.com/transcom/mymove/pkg/services/move" movetaskorder "github.com/transcom/mymove/pkg/services/move_task_order" @@ -96,7 +97,7 @@ func (suite *HandlerSuite) TestUpdateMoveHandler() { suite.HandlerConfig(), movetaskorder.NewMoveTaskOrderUpdater( builder, - mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter), + mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), moveRouter, ), } diff --git a/pkg/handlers/adminapi/office_users_test.go b/pkg/handlers/adminapi/office_users_test.go index 658f40cd180..6b98c3ea9f8 100644 --- a/pkg/handlers/adminapi/office_users_test.go +++ b/pkg/handlers/adminapi/office_users_test.go @@ -29,8 +29,8 @@ import ( func (suite *HandlerSuite) TestIndexOfficeUsersHandler() { setupTestData := func() models.OfficeUsers { return models.OfficeUsers{ - factory.BuildOfficeUserWithRoles(suite.DB(), factory.GetTraitApprovedOfficeUser(), []roles.RoleType{roles.RoleTypeQaeCsr}), - factory.BuildOfficeUserWithRoles(suite.DB(), factory.GetTraitApprovedOfficeUser(), []roles.RoleType{roles.RoleTypeQaeCsr}), + factory.BuildOfficeUserWithRoles(suite.DB(), factory.GetTraitApprovedOfficeUser(), []roles.RoleType{roles.RoleTypeQae}), + factory.BuildOfficeUserWithRoles(suite.DB(), factory.GetTraitApprovedOfficeUser(), []roles.RoleType{roles.RoleTypeQae}), } } diff --git a/pkg/handlers/adminapi/requested_office_users_test.go b/pkg/handlers/adminapi/requested_office_users_test.go index 6fbfc095df5..fa179cf5167 100644 --- a/pkg/handlers/adminapi/requested_office_users_test.go +++ b/pkg/handlers/adminapi/requested_office_users_test.go @@ -29,8 +29,8 @@ func (suite *HandlerSuite) TestIndexRequestedOfficeUsersHandler() { suite.Run("requested users result in ok response", func() { // building two office user with requested status requestedOfficeUsers := models.OfficeUsers{ - factory.BuildOfficeUserWithRoles(suite.DB(), factory.GetTraitRequestedOfficeUser(), []roles.RoleType{roles.RoleTypeQaeCsr}), - factory.BuildOfficeUserWithRoles(suite.DB(), factory.GetTraitRequestedOfficeUser(), []roles.RoleType{roles.RoleTypeQaeCsr})} + factory.BuildOfficeUserWithRoles(suite.DB(), factory.GetTraitRequestedOfficeUser(), []roles.RoleType{roles.RoleTypeQae}), + factory.BuildOfficeUserWithRoles(suite.DB(), factory.GetTraitRequestedOfficeUser(), []roles.RoleType{roles.RoleTypeQae})} params := requestedofficeuserop.IndexRequestedOfficeUsersParams{ HTTPRequest: suite.setupAuthenticatedRequest("GET", "/requested_office_users"), } @@ -56,7 +56,7 @@ func (suite *HandlerSuite) TestIndexRequestedOfficeUsersHandler() { func (suite *HandlerSuite) TestGetRequestedOfficeUserHandler() { // test that everything is wired up suite.Run("integration test ok response", func() { - requestedOfficeUser := factory.BuildOfficeUserWithRoles(suite.DB(), factory.GetTraitRequestedOfficeUser(), []roles.RoleType{roles.RoleTypeQaeCsr}) + requestedOfficeUser := factory.BuildOfficeUserWithRoles(suite.DB(), factory.GetTraitRequestedOfficeUser(), []roles.RoleType{roles.RoleTypeQae}) params := requestedofficeuserop.GetRequestedOfficeUserParams{ HTTPRequest: suite.setupAuthenticatedRequest("GET", fmt.Sprintf("/requested_office_users/%s", requestedOfficeUser.ID)), OfficeUserID: strfmt.UUID(requestedOfficeUser.ID.String()), @@ -94,7 +94,7 @@ func (suite *HandlerSuite) TestGetRequestedOfficeUserHandler() { }) suite.Run("successful response", func() { - requestedOfficeUser := factory.BuildOfficeUserWithRoles(suite.DB(), factory.GetTraitRequestedOfficeUser(), []roles.RoleType{roles.RoleTypeQaeCsr}) + requestedOfficeUser := factory.BuildOfficeUserWithRoles(suite.DB(), factory.GetTraitRequestedOfficeUser(), []roles.RoleType{roles.RoleTypeQae}) params := requestedofficeuserop.GetRequestedOfficeUserParams{ HTTPRequest: suite.setupAuthenticatedRequest("GET", fmt.Sprintf("/requested_office_users/%s", requestedOfficeUser.ID)), OfficeUserID: strfmt.UUID(requestedOfficeUser.ID.String()), @@ -135,7 +135,7 @@ func (suite *HandlerSuite) TestGetRequestedOfficeUserHandler() { }) suite.Run("unsuccessful response when fetch fails", func() { - requestedOfficeUser := factory.BuildOfficeUserWithRoles(suite.DB(), factory.GetTraitRequestedOfficeUser(), []roles.RoleType{roles.RoleTypeQaeCsr}) + requestedOfficeUser := factory.BuildOfficeUserWithRoles(suite.DB(), factory.GetTraitRequestedOfficeUser(), []roles.RoleType{roles.RoleTypeQae}) params := requestedofficeuserop.GetRequestedOfficeUserParams{ HTTPRequest: suite.setupAuthenticatedRequest("GET", fmt.Sprintf("/requested_office_users/%s", requestedOfficeUser.ID)), OfficeUserID: strfmt.UUID(requestedOfficeUser.ID.String()), diff --git a/pkg/handlers/authentication/auth_test.go b/pkg/handlers/authentication/auth_test.go index 0f729e8e351..bac98391362 100644 --- a/pkg/handlers/authentication/auth_test.go +++ b/pkg/handlers/authentication/auth_test.go @@ -429,10 +429,10 @@ func (suite *AuthSuite) TestRequirePermissionsMiddlewareAuthorized() { // Test permissions middleware with a user who will be DENIED POST access on the endpoint: ghc/v1/shipments/:shipmentID/approve // role must NOT have update.shipment permissions func (suite *AuthSuite) TestRequirePermissionsMiddlewareUnauthorized() { - // QAECSR users will be denied access as they lack the proper permissions for our test - update.shipment - qaeCsrOfficeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeQaeCsr}) + // QAE users will be denied access as they lack the proper permissions for our test - update.shipment + qaeOfficeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeQae}) - identity, err := models.FetchUserIdentity(suite.DB(), qaeCsrOfficeUser.User.OktaID) + identity, err := models.FetchUserIdentity(suite.DB(), qaeOfficeUser.User.OktaID) suite.NoError(err) @@ -442,7 +442,7 @@ func (suite *AuthSuite) TestRequirePermissionsMiddlewareUnauthorized() { // And: the context contains the auth values handlerSession := auth.Session{ - UserID: qaeCsrOfficeUser.User.ID, + UserID: qaeOfficeUser.User.ID, IDToken: "fake Token", ApplicationName: "mil", } @@ -465,7 +465,7 @@ func (suite *AuthSuite) TestRequirePermissionsMiddlewareUnauthorized() { middleware(handler).ServeHTTP(rr, req) suite.Equal(http.StatusUnauthorized, rr.Code, "handler returned wrong status code") - suite.Equal(handlerSession.UserID, qaeCsrOfficeUser.User.ID, "the authenticated user is different from expected") + suite.Equal(handlerSession.UserID, qaeOfficeUser.User.ID, "the authenticated user is different from expected") } func (suite *AuthSuite) TestIsLoggedInWhenNoUserLoggedIn() { @@ -1424,7 +1424,7 @@ func (suite *AuthSuite) TestAuthorizeUnknownUserOfficeLogsInWithPermissions() { Model: user, LinkOnly: true, }, - }, []roles.RoleType{roles.RoleTypeQaeCsr}) + }, []roles.RoleType{roles.RoleTypeQae}) handlerConfig := suite.HandlerConfig() appnames := handlerConfig.AppNames() @@ -1460,13 +1460,13 @@ func (suite *AuthSuite) TestAuthorizeUnknownUserOfficeLogsInWithPermissions() { suite.NotEqual("", foundUser.CurrentOfficeSessionID) // Make sure session contains roles and permissions suite.NotEmpty(session.Roles) - userRole, hasRole := officeUser.User.Roles.GetRole(roles.RoleTypeQaeCsr) + userRole, hasRole := officeUser.User.Roles.GetRole(roles.RoleTypeQae) suite.True(hasRole) - sessionRole, hasRole := session.Roles.GetRole(roles.RoleTypeQaeCsr) + sessionRole, hasRole := session.Roles.GetRole(roles.RoleTypeQae) suite.True(hasRole) suite.Equal(userRole.ID, sessionRole.ID) suite.NotEmpty(session.Permissions) - suite.ElementsMatch(QAECSR.Permissions, session.Permissions) + suite.ElementsMatch(QAE.Permissions, session.Permissions) } func (suite *AuthSuite) TestAuthorizeUnknownUserAdminDeactivated() { diff --git a/pkg/handlers/authentication/devlocal.go b/pkg/handlers/authentication/devlocal.go index 109475dc2c3..ad0f78c9625 100644 --- a/pkg/handlers/authentication/devlocal.go +++ b/pkg/handlers/authentication/devlocal.go @@ -31,8 +31,10 @@ const ( ServicesCounselorOfficeUserType string = "Services Counselor office" // PrimeSimulatorOfficeUserType is the type of user for an Office user PrimeSimulatorOfficeUserType string = "Prime Simulator office" - // QaeCsrOfficeUserType is a type of user for an Office user - QaeCsrOfficeUserType string = "QAE/CSR office" + // QaeOfficeUserType is a type of user for an Office user + QaeOfficeUserType string = "QAE office" + // CustomerServiceRepresentativeOfficeUserType is the Customer Service Representative type of user for an Office user + CustomerServiceRepresentativeOfficeUserType string = "CSR office" // MultiRoleOfficeUserType has all the Office user roles MultiRoleOfficeUserType string = "Multi role office" // AdminUserType is the type of user for an admin user @@ -93,22 +95,23 @@ func (h UserListHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } type TemplateData struct { - Identities []models.UserIdentity - Gblocs []string - GblocDefault string - IsMilApp bool - MilMoveUserType string - IsOfficeApp bool - TOOOfficeUserType string - TIOOfficeUserType string - ServicesCounselorOfficeUserType string - PrimeSimulatorOfficeUserType string - QaeCsrOfficeUserType string - MultiRoleOfficeUserType string - IsAdminApp bool - AdminUserType string - CsrfToken string - QueryLimit int + Identities []models.UserIdentity + Gblocs []string + GblocDefault string + IsMilApp bool + MilMoveUserType string + IsOfficeApp bool + TOOOfficeUserType string + TIOOfficeUserType string + ServicesCounselorOfficeUserType string + PrimeSimulatorOfficeUserType string + QaeOfficeUserType string + CustomerServiceRepresentativeOfficeUserType string + MultiRoleOfficeUserType string + IsAdminApp bool + AdminUserType string + CsrfToken string + QueryLimit int } templateData := TemplateData{ @@ -122,10 +125,11 @@ func (h UserListHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { TIOOfficeUserType: TIOOfficeUserType, ServicesCounselorOfficeUserType: ServicesCounselorOfficeUserType, PrimeSimulatorOfficeUserType: PrimeSimulatorOfficeUserType, - QaeCsrOfficeUserType: QaeCsrOfficeUserType, - MultiRoleOfficeUserType: MultiRoleOfficeUserType, - IsAdminApp: auth.AdminApp == appCtx.Session().ApplicationName, - AdminUserType: AdminUserType, + QaeOfficeUserType: QaeOfficeUserType, + CustomerServiceRepresentativeOfficeUserType: CustomerServiceRepresentativeOfficeUserType, + MultiRoleOfficeUserType: MultiRoleOfficeUserType, + IsAdminApp: auth.AdminApp == appCtx.Session().ApplicationName, + AdminUserType: AdminUserType, // Build CSRF token instead of grabbing from middleware. Otherwise throws errors when accessed directly. CsrfToken: csrf.Token(r), QueryLimit: limit, @@ -247,12 +251,21 @@ func (h UserListHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {

- + ` + gblocSelectHTML + ` - +

+
+

+ + + ` + gblocSelectHTML + ` + +

+
+

@@ -753,7 +766,7 @@ func createUser(h devlocalAuthHandler, w http.ResponseWriter, r *http.Request) ( if verrs.HasAny() { appCtx.Logger().Error("validation errors creating office user", zap.Stringer("errors", verrs)) } - case QaeCsrOfficeUserType: + case QaeOfficeUserType: // Now create the Truss JPPSO address := models.Address{ StreetAddress1: "1333 Minna St", @@ -772,9 +785,9 @@ func createUser(h devlocalAuthHandler, w http.ResponseWriter, r *http.Request) ( } role := roles.Role{} - err = appCtx.DB().Where("role_type = $1", roles.RoleTypeQaeCsr).First(&role) + err = appCtx.DB().Where("role_type = $1", roles.RoleTypeQae).First(&role) if err != nil { - appCtx.Logger().Error("could not fetch role qae_csr", zap.Error(err)) + appCtx.Logger().Error("could not fetch role qae", zap.Error(err)) } usersRole := models.UsersRoles{ @@ -819,6 +832,78 @@ func createUser(h devlocalAuthHandler, w http.ResponseWriter, r *http.Request) ( officeUser.UserID = &user.ID } + verrs, err = appCtx.DB().ValidateAndSave(&officeUser) + if err != nil { + appCtx.Logger().Error("could not create office user", zap.Error(err)) + } + if verrs.HasAny() { + appCtx.Logger().Error("validation errors creating office user", zap.Stringer("errors", verrs)) + } + case CustomerServiceRepresentativeOfficeUserType: + address := models.Address{ + StreetAddress1: "1333 Minna St", + City: "San Francisco", + State: "CA", + PostalCode: "94115", + County: "SAINT CLAIR", + } + + verrs, err := appCtx.DB().ValidateAndSave(&address) + if err != nil { + appCtx.Logger().Error("could not create address", zap.Error(err)) + } + if verrs.HasAny() { + appCtx.Logger().Error("validation errors creating address", zap.Stringer("errors", verrs)) + } + + role := roles.Role{} + err = appCtx.DB().Where("role_type = $1", roles.RoleTypeCustomerServiceRepresentative).First(&role) + if err != nil { + appCtx.Logger().Error("could not fetch role customer_service_representative", zap.Error(err)) + } + + usersRole := models.UsersRoles{ + UserID: user.ID, + RoleID: role.ID, + } + + verrs, err = appCtx.DB().ValidateAndSave(&usersRole) + if err != nil { + appCtx.Logger().Error("could not create user role", zap.Error(err)) + } + if verrs.HasAny() { + appCtx.Logger().Error("validation errors creating user role", zap.Stringer("errors", verrs)) + } + + office := models.TransportationOffice{ + Name: "Transcom", + AddressID: address.ID, + Latitude: 37.7678355, + Longitude: -122.4199298, + Hours: models.StringPointer("0900-1800 Mon-Sat"), + Gbloc: gbloc, + } + + verrs, err = appCtx.DB().ValidateAndSave(&office) + if err != nil { + appCtx.Logger().Error("could not create office", zap.Error(err)) + } + if verrs.HasAny() { + appCtx.Logger().Error("validation errors creating office", zap.Stringer("errors", verrs)) + } + + officeUser := models.OfficeUser{ + FirstName: firstName, + LastName: lastName, + Telephone: telephone, + TransportationOfficeID: office.ID, + Email: email, + Active: true, + } + if user.ID != uuid.Nil { + officeUser.UserID = &user.ID + } + verrs, err = appCtx.DB().ValidateAndSave(&officeUser) if err != nil { appCtx.Logger().Error("could not create office user", zap.Error(err)) @@ -957,7 +1042,7 @@ func createSession(h devlocalAuthHandler, user *models.User, userType string, _ // Keep the logic for redirection separate from setting the session user ids switch userType { - case TOOOfficeUserType, TIOOfficeUserType, ServicesCounselorOfficeUserType, PrimeSimulatorOfficeUserType, QaeCsrOfficeUserType, MultiRoleOfficeUserType: + case TOOOfficeUserType, TIOOfficeUserType, ServicesCounselorOfficeUserType, PrimeSimulatorOfficeUserType, QaeOfficeUserType, CustomerServiceRepresentativeOfficeUserType, MultiRoleOfficeUserType: session.ApplicationName = auth.OfficeApp session.Hostname = h.AppNames().OfficeServername active = userIdentity.Active || (userIdentity.OfficeActive != nil && *userIdentity.OfficeActive) @@ -1045,7 +1130,7 @@ func loginUser(h devlocalAuthHandler, user *models.User, userType string, w http } func isOfficeUser(userType string) bool { - if userType == TOOOfficeUserType || userType == TIOOfficeUserType || userType == ServicesCounselorOfficeUserType || userType == QaeCsrOfficeUserType { + if userType == TOOOfficeUserType || userType == TIOOfficeUserType || userType == ServicesCounselorOfficeUserType || userType == QaeOfficeUserType || userType == CustomerServiceRepresentativeOfficeUserType { return true } return false diff --git a/pkg/handlers/authentication/devlocal_test.go b/pkg/handlers/authentication/devlocal_test.go index abfc4cc7ec8..6106e1c7b63 100644 --- a/pkg/handlers/authentication/devlocal_test.go +++ b/pkg/handlers/authentication/devlocal_test.go @@ -77,7 +77,10 @@ func (suite *AuthSuite) TestCreateUserHandlerOffice() { factory.GetTraitServicesCounselorRole, }) factory.BuildRole(suite.DB(), nil, []factory.Trait{ - factory.GetTraitQaeCsrRole, + factory.GetTraitQaeRole, + }) + factory.BuildRole(suite.DB(), nil, []factory.Trait{ + factory.GetTraitCustomerServiceRepresentativeRole, }) factory.BuildRole(suite.DB(), nil, []factory.Trait{ factory.GetTraitPrimeSimulatorRole, @@ -111,9 +114,14 @@ func (suite *AuthSuite) TestCreateUserHandlerOffice() { email: "services_counselor_office_user@example.com", }, { - userType: QaeCsrOfficeUserType, - roleTypes: []roles.RoleType{roles.RoleTypeQaeCsr}, - email: "qae_csr_office_user@example.com", + userType: QaeOfficeUserType, + roleTypes: []roles.RoleType{roles.RoleTypeQae}, + email: "qae_office_user@example.com", + }, + { + userType: CustomerServiceRepresentativeOfficeUserType, + roleTypes: []roles.RoleType{roles.RoleTypeCustomerServiceRepresentative}, + email: "customer_service_representative_office_user@example.com", }, { userType: PrimeSimulatorOfficeUserType, diff --git a/pkg/handlers/authentication/permissions.go b/pkg/handlers/authentication/permissions.go index 2a14b88daed..1c950469924 100644 --- a/pkg/handlers/authentication/permissions.go +++ b/pkg/handlers/authentication/permissions.go @@ -75,8 +75,8 @@ var ServicesCounselor = RolePermissions{ }, } -var QAECSR = RolePermissions{ - RoleType: roles.RoleTypeQaeCsr, +var QAE = RolePermissions{ + RoleType: roles.RoleTypeQae, Permissions: []string{ "create.reportViolation", "create.evaluationReport", @@ -88,7 +88,16 @@ var QAECSR = RolePermissions{ }, } -var AllRolesPermissions = []RolePermissions{TOO, TIO, ServicesCounselor, QAECSR} +var CustomerServiceRepresentative = RolePermissions{ + RoleType: roles.RoleTypeCustomerServiceRepresentative, + Permissions: []string{ + "read.paymentRequest", + "view.closeoutOffice", + "read.shipmentsPaymentSITBalance", + }, +} + +var AllRolesPermissions = []RolePermissions{TOO, TIO, ServicesCounselor, QAE, CustomerServiceRepresentative} // check if a [user.role] has permissions on a given object func checkUserPermission(appCtx appcontext.AppContext, session *auth.Session, permission string) (bool, error) { diff --git a/pkg/handlers/ghcapi/api.go b/pkg/handlers/ghcapi/api.go index a8795a869ef..12929837c93 100644 --- a/pkg/handlers/ghcapi/api.go +++ b/pkg/handlers/ghcapi/api.go @@ -68,7 +68,7 @@ func NewGhcAPIHandler(handlerConfig handlers.HandlerConfig) *ghcops.MymoveAPI { newRolesFetcher := roles.NewRolesFetcher() moveTaskOrderUpdater := movetaskorder.NewMoveTaskOrderUpdater( queryBuilder, - mtoserviceitem.NewMTOServiceItemCreator(handlerConfig.HHGPlanner(), queryBuilder, moveRouter), + mtoserviceitem.NewMTOServiceItemCreator(handlerConfig.HHGPlanner(), queryBuilder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), moveRouter, ) SSWPPMComputer := shipmentsummaryworksheet.NewSSWPPMComputer() @@ -364,8 +364,9 @@ func NewGhcAPIHandler(handlerConfig handlers.HandlerConfig) *ghcops.MymoveAPI { handlerConfig, mtoshipment.NewShipmentApprover( mtoshipment.NewShipmentRouter(), - mtoserviceitem.NewMTOServiceItemCreator(handlerConfig.HHGPlanner(), queryBuilder, moveRouter), + mtoserviceitem.NewMTOServiceItemCreator(handlerConfig.HHGPlanner(), queryBuilder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), handlerConfig.HHGPlanner(), + move.NewMoveWeights(mtoshipment.NewShipmentReweighRequester()), ), shipmentSITStatus, } @@ -609,5 +610,7 @@ func NewGhcAPIHandler(handlerConfig handlers.HandlerConfig) *ghcops.MymoveAPI { CustomerSearcher: customer.NewCustomerSearcher(), } + ghcAPI.ApplicationParametersGetParamHandler = ApplicationParametersParamHandler{handlerConfig} + return ghcAPI } diff --git a/pkg/handlers/ghcapi/application_parameters.go b/pkg/handlers/ghcapi/application_parameters.go new file mode 100644 index 00000000000..14fe02c2c9c --- /dev/null +++ b/pkg/handlers/ghcapi/application_parameters.go @@ -0,0 +1,46 @@ +package ghcapi + +import ( + "github.com/go-openapi/runtime/middleware" + + "github.com/transcom/mymove/pkg/appcontext" + "github.com/transcom/mymove/pkg/gen/ghcapi/ghcoperations/application_parameters" + "github.com/transcom/mymove/pkg/gen/ghcmessages" + "github.com/transcom/mymove/pkg/handlers" + "github.com/transcom/mymove/pkg/models" +) + +func payloadForApplicationParametersModel(v models.ApplicationParameters) ghcmessages.ApplicationParameters { + + parameterValue := v.ParameterValue + parameterName := v.ParameterName + + payload := ghcmessages.ApplicationParameters{ + ParameterValue: parameterValue, + ParameterName: parameterName, + } + return payload +} + +// ApplicationParametersValidateHandler validates a value provided by the service member +type ApplicationParametersParamHandler struct { + handlers.HandlerConfig +} + +// Handler receives a GET request containing a parameter name +// if the name is present, it returns the value back, if not, it returns an empty object +func (h ApplicationParametersParamHandler) Handle(params application_parameters.GetParamParams) middleware.Responder { + return h.AuditableAppContextFromRequestWithErrors(params.HTTPRequest, + func(appCtx appcontext.AppContext) (middleware.Responder, error) { + + // receive the value + name := params.ParameterName + + // fetch the value, if not found it will be an empty string + result, _ := models.FetchParameterValueByName(appCtx.DB(), name) + + parameterValuePayload := payloadForApplicationParametersModel(result) + + return application_parameters.NewGetParamOK().WithPayload(¶meterValuePayload), nil + }) +} diff --git a/pkg/handlers/ghcapi/application_parameters_test.go b/pkg/handlers/ghcapi/application_parameters_test.go new file mode 100644 index 00000000000..86367daf926 --- /dev/null +++ b/pkg/handlers/ghcapi/application_parameters_test.go @@ -0,0 +1,29 @@ +package ghcapi + +import ( + "net/http/httptest" + + "github.com/transcom/mymove/pkg/factory" + "github.com/transcom/mymove/pkg/gen/ghcapi/ghcoperations/application_parameters" +) + +func (suite *HandlerSuite) TestApplicationParametersValidateHandler() { + user := factory.BuildDefaultUser(suite.DB()) + + req := httptest.NewRequest("GET", "/application_parameters", nil) + req = suite.AuthenticateUserRequest(req, user) + + handlerConfig := suite.HandlerConfig() + handler := ApplicationParametersParamHandler{ + HandlerConfig: handlerConfig, + } + + params := application_parameters.GetParamParams{ + HTTPRequest: req, + ParameterName: "standaloneCrateCap", + } + + response := handler.Handle(params) + + suite.Assertions.IsType(&application_parameters.GetParamOK{}, response) +} diff --git a/pkg/handlers/ghcapi/internal/payloads/model_to_payload.go b/pkg/handlers/ghcapi/internal/payloads/model_to_payload.go index fb871d5c10c..083d84aa620 100644 --- a/pkg/handlers/ghcapi/internal/payloads/model_to_payload.go +++ b/pkg/handlers/ghcapi/internal/payloads/model_to_payload.go @@ -483,7 +483,7 @@ func Customer(customer *models.ServiceMember) *ghcmessages.Customer { SecondaryTelephone: customer.SecondaryTelephone, PhoneIsPreferred: swag.BoolValue(customer.PhoneIsPreferred), EmailIsPreferred: swag.BoolValue(customer.EmailIsPreferred), - CacValidated: swag.BoolValue(&customer.CacValidated), + CacValidated: &customer.CacValidated, } return &payload } @@ -985,6 +985,11 @@ func MovingExpense(storer storage.FileStorer, movingExpense *models.MovingExpens payload.WeightStored = handlers.FmtPoundPtr(movingExpense.WeightStored) } + if movingExpense.SITLocation != nil { + sitLocation := ghcmessages.SITLocationType(*movingExpense.SITLocation) + payload.SitLocation = &sitLocation + } + return payload } @@ -1509,6 +1514,8 @@ func MTOServiceItemModel(s *models.MTOServiceItem, storer storage.FileStorer) *g ConvertToCustomerExpense: *handlers.FmtBool(s.CustomerExpense), CustomerExpenseReason: handlers.FmtStringPtr(s.CustomerExpenseReason), SitDeliveryMiles: handlers.FmtIntPtrToInt64(s.SITDeliveryMiles), + EstimatedPrice: handlers.FmtCost(s.PricingEstimate), + StandaloneCrate: s.StandaloneCrate, } } diff --git a/pkg/handlers/ghcapi/internal/payloads/payload_to_model.go b/pkg/handlers/ghcapi/internal/payloads/payload_to_model.go index b89c265731c..ff43c017205 100644 --- a/pkg/handlers/ghcapi/internal/payloads/payload_to_model.go +++ b/pkg/handlers/ghcapi/internal/payloads/payload_to_model.go @@ -581,6 +581,10 @@ func MovingExpenseModelFromUpdate(movingExpense *ghcmessages.UpdateMovingExpense model.Description = movingExpense.Description } + if movingExpense.SitLocation != nil { + model.SITLocation = (*models.SITLocationType)(handlers.FmtString(string(*movingExpense.SitLocation))) + } + model.Amount = handlers.FmtInt64PtrToPopPtr(&movingExpense.Amount) model.SITStartDate = handlers.FmtDatePtrToPopPtr(&movingExpense.SitStartDate) model.SITEndDate = handlers.FmtDatePtrToPopPtr(&movingExpense.SitEndDate) diff --git a/pkg/handlers/ghcapi/move.go b/pkg/handlers/ghcapi/move.go index 7cb8caa553b..2c75a267277 100644 --- a/pkg/handlers/ghcapi/move.go +++ b/pkg/handlers/ghcapi/move.go @@ -15,6 +15,7 @@ import ( "github.com/transcom/mymove/pkg/gen/ghcmessages" "github.com/transcom/mymove/pkg/handlers" "github.com/transcom/mymove/pkg/handlers/ghcapi/internal/payloads" + "github.com/transcom/mymove/pkg/models" "github.com/transcom/mymove/pkg/services" ) @@ -46,6 +47,11 @@ func (h GetMoveHandler) Handle(params moveop.GetMoveParams) middleware.Responder } } + privileges, err := models.FetchPrivilegesForUser(appCtx.DB(), appCtx.Session().UserID) + if err != nil { + appCtx.Logger().Error("Error retreiving user privileges", zap.Error(err)) + } + // if this user is accessing the move record, we need to lock it so others can't edit it // to allow for locking a move, we need to look at these things // 1. Is the user an office user? @@ -66,8 +72,18 @@ func (h GetMoveHandler) Handle(params moveop.GetMoveParams) middleware.Responder } } - payload := payloads.Move(move) - return moveop.NewGetMoveOK().WithPayload(payload), nil + moveOrders, err := models.FetchOrder(appCtx.DB(), move.OrdersID) + if err != nil { + appCtx.Logger().Error("Error retreiving user privileges", zap.Error(err)) + } + + if moveOrders.OrdersType == "SAFETY" && !privileges.HasPrivilege(models.PrivilegeTypeSafety) { + appCtx.Logger().Error("Invalid permissions") + return moveop.NewGetMoveNotFound(), nil + } else { + payload := payloads.Move(move) + return moveop.NewGetMoveOK().WithPayload(payload), nil + } }) } diff --git a/pkg/handlers/ghcapi/move_task_order_test.go b/pkg/handlers/ghcapi/move_task_order_test.go index c411fb70618..9e6e8481032 100644 --- a/pkg/handlers/ghcapi/move_task_order_test.go +++ b/pkg/handlers/ghcapi/move_task_order_test.go @@ -29,6 +29,7 @@ import ( "github.com/transcom/mymove/pkg/models/roles" "github.com/transcom/mymove/pkg/notifications" routemocks "github.com/transcom/mymove/pkg/route/mocks" + "github.com/transcom/mymove/pkg/services/ghcrateengine" "github.com/transcom/mymove/pkg/services/mocks" moverouter "github.com/transcom/mymove/pkg/services/move" movetaskorder "github.com/transcom/mymove/pkg/services/move_task_order" @@ -120,7 +121,7 @@ func (suite *HandlerSuite) TestUpdateMoveTaskOrderHandlerIntegrationSuccess() { mock.Anything, mock.Anything, ).Return(400, nil) - siCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter) + siCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) // setup the handler handler := UpdateMoveTaskOrderStatusHandlerFunc{handlerConfig, @@ -242,7 +243,7 @@ func (suite *HandlerSuite) TestUpdateMoveTaskOrderHandlerIntegrationWithIncomple mock.Anything, mock.Anything, ).Return(400, nil) - siCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter) + siCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) // make the request handler := UpdateMoveTaskOrderStatusHandlerFunc{handlerConfig, @@ -278,7 +279,7 @@ func (suite *HandlerSuite) TestUpdateMTOStatusServiceCounselingCompletedHandler( mock.Anything, mock.Anything, ).Return(400, nil) - siCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter) + siCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := UpdateMTOStatusServiceCounselingCompletedHandlerFunc{ handlerConfig, movetaskorder.NewMoveTaskOrderUpdater(queryBuilder, siCreator, moveRouter), @@ -496,7 +497,7 @@ func (suite *HandlerSuite) TestUpdateMoveTIORemarksHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - siCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter) + siCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := UpdateMoveTIORemarksHandlerFunc{ handlerConfig, movetaskorder.NewMoveTaskOrderUpdater(queryBuilder, siCreator, moveRouter), diff --git a/pkg/handlers/ghcapi/move_test.go b/pkg/handlers/ghcapi/move_test.go index 89c17207769..aef8ba17471 100644 --- a/pkg/handlers/ghcapi/move_test.go +++ b/pkg/handlers/ghcapi/move_test.go @@ -111,7 +111,7 @@ func (suite *HandlerSuite) TestGetMoveHandler() { Type: &factory.TransportationOffices.CloseoutOffice, }, }, nil) - moveFetcher := moveservice.NewMoveFetcher() + mockFetcher := mocks.MoveFetcher{} mockLocker := movelocker.NewMoveLocker() requestOfficeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeServicesCounselor}) @@ -126,10 +126,16 @@ func (suite *HandlerSuite) TestGetMoveHandler() { handler := GetMoveHandler{ HandlerConfig: suite.HandlerConfig(), - MoveFetcher: moveFetcher, + MoveFetcher: &mockFetcher, MoveLocker: mockLocker, } + mockFetcher.On("FetchMove", + mock.AnythingOfType("*appcontext.appContext"), + move.Locator, + mock.Anything, + ).Return(&move, nil) + response := handler.Handle(params) suite.IsType(&moveops.GetMoveOK{}, response) payload := response.(*moveops.GetMoveOK).Payload @@ -228,6 +234,40 @@ func (suite *HandlerSuite) TestGetMoveHandler() { // Validate outgoing payload: nil payload suite.Nil(payload) }) + + suite.Run("Unsuccessful move fetch - invalid privileges", func() { + setupTestData() + mockFetcher := mocks.MoveFetcher{} + mockLocker := movelocker.NewMoveLocker() + + handler := GetMoveHandler{ + HandlerConfig: suite.HandlerConfig(), + MoveFetcher: &mockFetcher, + MoveLocker: mockLocker, + } + + mockFetcher.On("FetchMove", + mock.AnythingOfType("*appcontext.appContext"), + move.Locator, + mock.Anything, + ).Return(&models.Move{}, apperror.NotFoundError{}) + + req := httptest.NewRequest("GET", "/move/#{move.locator}", nil) + req = suite.AuthenticateUserRequest(req, requestUser.User) + params := moveops.GetMoveParams{ + HTTPRequest: req, + Locator: move.Locator, + } + + // Validate incoming payload: no body to validate + + response := handler.Handle(params) + suite.IsType(&moveops.GetMoveNotFound{}, response) + payload := response.(*moveops.GetMoveNotFound).Payload + + // Validate outgoing payload: nil payload + suite.Nil(payload) + }) } func (suite *HandlerSuite) TestSearchMovesHandler() { diff --git a/pkg/handlers/ghcapi/moving_expense_test.go b/pkg/handlers/ghcapi/moving_expense_test.go index df9a9a21d19..155ea4464d2 100644 --- a/pkg/handlers/ghcapi/moving_expense_test.go +++ b/pkg/handlers/ghcapi/moving_expense_test.go @@ -31,7 +31,7 @@ func (suite *HandlerSuite) TestUpdateMovingExpenseHandlerUnit() { suite.FatalNoError(err) - ppmShipment = factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), userUploader, nil) + ppmShipment = factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), userUploader, nil) ppmShipment.MovingExpenses = append( ppmShipment.MovingExpenses, @@ -242,7 +242,7 @@ func (suite *HandlerSuite) TestUpdateMovingExpenseHandlerIntegration() { suite.FatalNoError(err) - ppmShipment = factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), userUploader, nil) + ppmShipment = factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), userUploader, nil) packingMaterialsType := models.MovingExpenseReceiptTypePackingMaterials movingExpense = factory.BuildMovingExpense(suite.DB(), []factory.Customization{ diff --git a/pkg/handlers/ghcapi/mto_shipment.go b/pkg/handlers/ghcapi/mto_shipment.go index 1e06725d36f..96e3ee1ed84 100644 --- a/pkg/handlers/ghcapi/mto_shipment.go +++ b/pkg/handlers/ghcapi/mto_shipment.go @@ -23,6 +23,7 @@ import ( "github.com/transcom/mymove/pkg/services" "github.com/transcom/mymove/pkg/services/event" mtoshipment "github.com/transcom/mymove/pkg/services/mto_shipment" + ppmshipment "github.com/transcom/mymove/pkg/services/ppmshipment" ) // ListMTOShipmentsHandler returns a list of MTO Shipments @@ -108,6 +109,26 @@ func (h GetMTOShipmentHandler) Handle(params mtoshipmentops.GetShipmentParams) m return handleError(err) } + if mtoShipment.ShipmentType == models.MTOShipmentTypePPM { + ppmEagerAssociations := []string{"PickupAddress", + "DestinationAddress", + "SecondaryPickupAddress", + "SecondaryDestinationAddress", + } + + ppmShipmentFetcher := ppmshipment.NewPPMShipmentFetcher() + + ppmShipment, err := ppmShipmentFetcher.GetPPMShipment(appCtx, mtoShipment.PPMShipment.ID, ppmEagerAssociations, nil) + if err != nil { + return handleError(err) + } + + mtoShipment.PPMShipment.PickupAddress = ppmShipment.PickupAddress + mtoShipment.PPMShipment.DestinationAddress = ppmShipment.DestinationAddress + mtoShipment.PPMShipment.SecondaryPickupAddress = ppmShipment.SecondaryPickupAddress + mtoShipment.PPMShipment.SecondaryDestinationAddress = ppmShipment.SecondaryDestinationAddress + } + var agents []models.MTOAgent err = appCtx.DB().Scope(utilities.ExcludeDeletedScope()).Where("mto_shipment_id = ?", mtoShipment.ID).All(&agents) if err != nil { diff --git a/pkg/handlers/ghcapi/mto_shipment_test.go b/pkg/handlers/ghcapi/mto_shipment_test.go index 8bcae85556d..cd13ed0d53b 100644 --- a/pkg/handlers/ghcapi/mto_shipment_test.go +++ b/pkg/handlers/ghcapi/mto_shipment_test.go @@ -312,7 +312,7 @@ func (suite *HandlerSuite) TestListMTOShipmentsHandler() { func (suite *HandlerSuite) TestDeleteShipmentHandler() { suite.Run("Returns a 403 when user is not a service counselor or TOO", func() { - officeUser := factory.BuildOfficeUserWithRoles(nil, nil, []roles.RoleType{roles.RoleTypeQaeCsr}) + officeUser := factory.BuildOfficeUserWithRoles(nil, nil, []roles.RoleType{roles.RoleTypeQae}) uuid := uuid.Must(uuid.NewV4()) deleter := &mocks.ShipmentDeleter{} @@ -607,6 +607,7 @@ func (suite *HandlerSuite) TestApproveShipmentHandler() { builder := query.NewQueryBuilder() moveRouter := moveservices.NewMoveRouter() planner := &routemocks.Planner{} + moveWeights := moveservices.NewMoveWeights(mtoshipment.NewShipmentReweighRequester()) planner.On("ZipTransitDistance", mock.AnythingOfType("*appcontext.appContext"), mock.Anything, @@ -614,8 +615,9 @@ func (suite *HandlerSuite) TestApproveShipmentHandler() { ).Return(400, nil) approver := mtoshipment.NewShipmentApprover( mtoshipment.NewShipmentRouter(), - mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter), + mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), &routemocks.Planner{}, + moveWeights, ) req := httptest.NewRequest("POST", fmt.Sprintf("/shipments/%s/approve", shipment.ID.String()), nil) @@ -3111,7 +3113,7 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandler() { ).Return(400, nil) moveTaskOrderUpdater := movetaskorder.NewMoveTaskOrderUpdater( builder, - mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter), + mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), moveRouter, ) shipmentCreator := shipmentorchestrator.NewShipmentCreator(creator, ppmCreator, shipmentRouter, moveTaskOrderUpdater) @@ -3193,7 +3195,7 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandler() { ).Return(400, nil) moveTaskOrderUpdater := movetaskorder.NewMoveTaskOrderUpdater( builder, - mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter), + mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), moveRouter, ) shipmentCreator := shipmentorchestrator.NewShipmentCreator(creator, ppmCreator, shipmentRouter, moveTaskOrderUpdater) @@ -3247,7 +3249,7 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandler() { ).Return(400, nil) moveTaskOrderUpdater := movetaskorder.NewMoveTaskOrderUpdater( builder, - mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter), + mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), moveRouter, ) shipmentCreator := shipmentorchestrator.NewShipmentCreator(creator, ppmCreator, shipmentRouter, moveTaskOrderUpdater) @@ -3297,7 +3299,7 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandler() { ).Return(400, nil) moveTaskOrderUpdater := movetaskorder.NewMoveTaskOrderUpdater( builder, - mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter), + mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), moveRouter, ) shipmentCreator := shipmentorchestrator.NewShipmentCreator(creator, ppmCreator, shipmentRouter, moveTaskOrderUpdater) @@ -3342,7 +3344,7 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandler() { ).Return(400, nil) moveTaskOrderUpdater := movetaskorder.NewMoveTaskOrderUpdater( builder, - mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter), + mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), moveRouter, ) shipmentCreator := shipmentorchestrator.NewShipmentCreator(creator, ppmCreator, shipmentRouter, moveTaskOrderUpdater) @@ -3398,7 +3400,7 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandlerUsingPPM() { ).Return(400, nil) moveTaskOrderUpdater := movetaskorder.NewMoveTaskOrderUpdater( builder, - mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveservices.NewMoveRouter()), + mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveservices.NewMoveRouter(), ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), moveservices.NewMoveRouter(), ) shipmentCreator := shipmentorchestrator.NewShipmentCreator(creator, ppmCreator, shipmentRouter, moveTaskOrderUpdater) @@ -3602,7 +3604,7 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandlerUsingPPM() { ).Return(400, nil) moveTaskOrderUpdater := movetaskorder.NewMoveTaskOrderUpdater( builder, - mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveservices.NewMoveRouter()), + mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveservices.NewMoveRouter(), ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), moveservices.NewMoveRouter(), ) shipmentCreator := shipmentorchestrator.NewShipmentCreator(creator, ppmshipment.NewPPMShipmentCreator(&ppmEstimator, addressCreator), shipmentRouter, moveTaskOrderUpdater) @@ -3744,7 +3746,7 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandlerUsingPPM() { ).Return(400, nil) moveTaskOrderUpdater := movetaskorder.NewMoveTaskOrderUpdater( builder, - mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveservices.NewMoveRouter()), + mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveservices.NewMoveRouter(), ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), moveservices.NewMoveRouter(), ) shipmentCreator := shipmentorchestrator.NewShipmentCreator(creator, ppmshipment.NewPPMShipmentCreator(&ppmEstimator, addressCreator), shipmentRouter, moveTaskOrderUpdater) diff --git a/pkg/handlers/ghcapi/office_users_test.go b/pkg/handlers/ghcapi/office_users_test.go index 995026d748b..fe8ba95b1f8 100644 --- a/pkg/handlers/ghcapi/office_users_test.go +++ b/pkg/handlers/ghcapi/office_users_test.go @@ -34,7 +34,7 @@ func (suite *HandlerSuite) setupOfficeUserCreatorTestScenario() (*mocks.OfficeUs } // Services Counselor. Task Ordering Officer (TOO), Task Invoicing Officer (TIO), -// and Quality Assurance Evaluator (QAE)/Customer Service Representative (CSR) +// Quality Assurance Evaluator (QAE), and Customer Service Representative (CSR) // Are all roles allowed to request office user (They authenticate with AuthenticateOfficeRequest) func (suite *HandlerSuite) TestRequestOfficeUserHandler() { suite.Run("Successfully requests the creation of an office user", func() { @@ -42,7 +42,7 @@ func (suite *HandlerSuite) TestRequestOfficeUserHandler() { transportationOffice := factory.BuildTransportationOffice(suite.DB(), nil, nil) - officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeTOO, roles.RoleTypeServicesCounselor, roles.RoleTypeTIO, roles.RoleTypeQaeCsr}) + officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeTOO, roles.RoleTypeServicesCounselor, roles.RoleTypeTIO, roles.RoleTypeQae}) request := httptest.NewRequest("POST", "/requested-office-users", nil) request = suite.AuthenticateOfficeRequest(request, officeUser) params := officeuserop.CreateRequestedOfficeUserParams{ @@ -231,7 +231,7 @@ func (suite *HandlerSuite) TestRequestOfficeUserHandler() { transportationOffice := factory.BuildTransportationOffice(suite.DB(), nil, nil) - officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeTOO, roles.RoleTypeServicesCounselor, roles.RoleTypeTIO, roles.RoleTypeQaeCsr}) + officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeTOO, roles.RoleTypeServicesCounselor, roles.RoleTypeTIO, roles.RoleTypeQae}) request := httptest.NewRequest("POST", "/requested-office-users", nil) request = suite.AuthenticateOfficeRequest(request, officeUser) // EDIPI and other unique ID missing diff --git a/pkg/handlers/ghcapi/orders_test.go b/pkg/handlers/ghcapi/orders_test.go index 1a18f6bd5c7..822d4d40471 100644 --- a/pkg/handlers/ghcapi/orders_test.go +++ b/pkg/handlers/ghcapi/orders_test.go @@ -19,6 +19,7 @@ import ( "github.com/transcom/mymove/pkg/models" "github.com/transcom/mymove/pkg/models/roles" routemocks "github.com/transcom/mymove/pkg/route/mocks" + "github.com/transcom/mymove/pkg/services/ghcrateengine" "github.com/transcom/mymove/pkg/services/mocks" moverouter "github.com/transcom/mymove/pkg/services/move" movetaskorder "github.com/transcom/mymove/pkg/services/move_task_order" @@ -317,7 +318,7 @@ func (suite *HandlerSuite) TestUpdateOrderHandlerWithAmendedUploads() { ).Return(400, nil) moveTaskOrderUpdater := movetaskorder.NewMoveTaskOrderUpdater( queryBuilder, - mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter), + mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), moveRouter, ) diff --git a/pkg/handlers/ghcapi/ppm_document_test.go b/pkg/handlers/ghcapi/ppm_document_test.go index cb0362ce8c9..3fe5e5c80f8 100644 --- a/pkg/handlers/ghcapi/ppm_document_test.go +++ b/pkg/handlers/ghcapi/ppm_document_test.go @@ -33,7 +33,7 @@ func (suite *HandlerSuite) TestGetPPMDocumentsHandlerUnit() { suite.FatalNoError(err) - ppmShipment = factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), userUploader, nil) + ppmShipment = factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), userUploader, nil) ppmShipment.WeightTickets = append( ppmShipment.WeightTickets, @@ -238,7 +238,7 @@ func (suite *HandlerSuite) TestGetPPMDocumentsHandlerIntegration() { suite.FatalNoError(err) - ppmShipment = factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), userUploader, nil) + ppmShipment = factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), userUploader, nil) ppmShipment.WeightTickets = append( ppmShipment.WeightTickets, @@ -454,7 +454,7 @@ func (suite *HandlerSuite) TestFinishPPMDocumentsReviewHandlerUnit() { _, params := setUpRequestAndParams(ppmShipment, true) expectedPPMShipment := ppmShipment - expectedPPMShipment.Status = models.PPMShipmentStatusPaymentApproved + expectedPPMShipment.Status = models.PPMShipmentStatusCloseoutComplete suite.FatalNotNil(expectedPPMShipment.SubmittedAt) @@ -519,7 +519,7 @@ func (suite *HandlerSuite) TestResubmitPPMShipmentDocumentationHandlerIntegratio }) suite.Run("Returns an error if the PPM shipment is not awaiting payment review", func() { - draftPpmShipment := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), nil, nil) + draftPpmShipment := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), nil, nil) draftPpmShipment.Status = models.PPMShipmentStatusDraft suite.NoError(suite.DB().Save(&draftPpmShipment)) @@ -531,7 +531,7 @@ func (suite *HandlerSuite) TestResubmitPPMShipmentDocumentationHandlerIntegratio }) suite.Run("Can successfully submit a PPM shipment for close out", func() { - ppmShipment := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), nil, nil) + ppmShipment := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), nil, nil) params, handler := setUpParamsAndHandler(ppmShipment, officeUser) @@ -544,13 +544,13 @@ func (suite *HandlerSuite) TestResubmitPPMShipmentDocumentationHandlerIntegratio suite.NoError(returnedPPMShipment.Validate(strfmt.Default)) suite.EqualUUID(ppmShipment.ID, returnedPPMShipment.ID) - suite.Equal(string(models.PPMShipmentStatusPaymentApproved), string(returnedPPMShipment.Status)) + suite.Equal(string(models.PPMShipmentStatusCloseoutComplete), string(returnedPPMShipment.Status)) } }) suite.Run("Sets PPM to await customer if there are rejected documents", func() { ppmShipment := factory.BuildPPMShipmentThatNeedsToBeResubmitted(suite.DB(), nil) - ppmShipment.Status = models.PPMShipmentStatusNeedsPaymentApproval + ppmShipment.Status = models.PPMShipmentStatusNeedsCloseout suite.NoError(suite.DB().Save(&ppmShipment)) params, handler := setUpParamsAndHandler(ppmShipment, officeUser) diff --git a/pkg/handlers/ghcapi/weight_ticket_test.go b/pkg/handlers/ghcapi/weight_ticket_test.go index 9d9f23495c4..406d103c521 100644 --- a/pkg/handlers/ghcapi/weight_ticket_test.go +++ b/pkg/handlers/ghcapi/weight_ticket_test.go @@ -34,7 +34,7 @@ func (suite *HandlerSuite) TestUpdateWeightTicketHandler() { makeUpdateSubtestData := func(_ bool) (subtestData weightTicketUpdateSubtestData) { // Use fake data: - subtestData.ppmShipment = factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), nil, nil) + subtestData.ppmShipment = factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), nil, nil) subtestData.weightTicket = subtestData.ppmShipment.WeightTickets[0] endpoint := fmt.Sprintf("/ppm-shipments/%s/weight-ticket/%s", subtestData.ppmShipment.ID.String(), subtestData.weightTicket.ID.String()) officeUser := factory.BuildOfficeUser(nil, nil, nil) diff --git a/pkg/handlers/internalapi/api.go b/pkg/handlers/internalapi/api.go index 0c6cd89f0d3..8f8cc16c317 100644 --- a/pkg/handlers/internalapi/api.go +++ b/pkg/handlers/internalapi/api.go @@ -176,7 +176,7 @@ func NewInternalAPI(handlerConfig handlers.HandlerConfig) *internalops.MymoveAPI shipmentRouter := mtoshipment.NewShipmentRouter() moveTaskOrderUpdater := movetaskorder.NewMoveTaskOrderUpdater( builder, - mtoserviceitem.NewMTOServiceItemCreator(handlerConfig.HHGPlanner(), builder, moveRouter), + mtoserviceitem.NewMTOServiceItemCreator(handlerConfig.HHGPlanner(), builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), moveRouter, ) shipmentCreator := shipment.NewShipmentCreator(mtoShipmentCreator, ppmshipment.NewPPMShipmentCreator(ppmEstimator, addressCreator), shipmentRouter, moveTaskOrderUpdater) diff --git a/pkg/handlers/internalapi/internal/payloads/model_to_payload.go b/pkg/handlers/internalapi/internal/payloads/model_to_payload.go index 7ac331214a1..e48a5664b0e 100644 --- a/pkg/handlers/internalapi/internal/payloads/model_to_payload.go +++ b/pkg/handlers/internalapi/internal/payloads/model_to_payload.go @@ -376,6 +376,11 @@ func MovingExpense(storer storage.FileStorer, movingExpense *models.MovingExpens payload.WeightStored = handlers.FmtPoundPtr(movingExpense.WeightStored) } + if movingExpense.SITLocation != nil { + sitLocation := internalmessages.SITLocationType(*movingExpense.SITLocation) + payload.SitLocation = &sitLocation + } + return payload } diff --git a/pkg/handlers/internalapi/internal/payloads/payload_to_model.go b/pkg/handlers/internalapi/internal/payloads/payload_to_model.go index cf00ed1d468..b8101f3a051 100644 --- a/pkg/handlers/internalapi/internal/payloads/payload_to_model.go +++ b/pkg/handlers/internalapi/internal/payloads/payload_to_model.go @@ -308,6 +308,10 @@ func MovingExpenseModelFromUpdate(movingExpense *internalmessages.UpdateMovingEx model.MissingReceipt = handlers.FmtBool(*movingExpense.MissingReceipt) } + if movingExpense.SitLocation != nil { + model.SITLocation = (*models.SITLocationType)(handlers.FmtString(string(*movingExpense.SitLocation))) + } + return model } diff --git a/pkg/handlers/internalapi/mto_shipment_test.go b/pkg/handlers/internalapi/mto_shipment_test.go index 8b2815b0665..b5cf3f4d64b 100644 --- a/pkg/handlers/internalapi/mto_shipment_test.go +++ b/pkg/handlers/internalapi/mto_shipment_test.go @@ -77,7 +77,7 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandlerV1() { ).Return(400, nil) moveTaskOrderUpdater := movetaskorder.NewMoveTaskOrderUpdater( testMTOShipmentObjects.builder, - mtoserviceitem.NewMTOServiceItemCreator(planner, testMTOShipmentObjects.builder, testMTOShipmentObjects.moveRouter), + mtoserviceitem.NewMTOServiceItemCreator(planner, testMTOShipmentObjects.builder, testMTOShipmentObjects.moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), testMTOShipmentObjects.moveRouter, ) shipmentCreator := shipmentorchestrator.NewShipmentCreator(mtoShipmentCreator, ppmShipmentCreator, shipmentRouter, moveTaskOrderUpdater) diff --git a/pkg/handlers/internalapi/ppm_shipment_test.go b/pkg/handlers/internalapi/ppm_shipment_test.go index 4fc1e840888..2a6377c8972 100644 --- a/pkg/handlers/internalapi/ppm_shipment_test.go +++ b/pkg/handlers/internalapi/ppm_shipment_test.go @@ -250,7 +250,7 @@ func (suite *HandlerSuite) TestSubmitPPMShipmentDocumentationHandlerUnit() { _, params := setUpRequestAndParams(ppmShipment.ID, ppmShipment.Shipment.MoveTaskOrder.Orders.ServiceMember, true) expectedPPMShipment := ppmShipment - expectedPPMShipment.Status = models.PPMShipmentStatusNeedsPaymentApproval + expectedPPMShipment.Status = models.PPMShipmentStatusNeedsCloseout expectedPPMShipment.SubmittedAt = models.TimePointer(time.Now()) move := ppmShipment.Shipment.MoveTaskOrder @@ -399,7 +399,7 @@ func (suite *HandlerSuite) TestSubmitPPMShipmentDocumentationHandlerIntegration( }) suite.Run("Returns an error if the PPM shipment is not in the right status", func() { - ppmShipment := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), nil, nil) + ppmShipment := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), nil, nil) params, handler := setUpParamsAndHandler( ppmShipment.ID, @@ -421,7 +421,7 @@ func (suite *HandlerSuite) TestSubmitPPMShipmentDocumentationHandlerIntegration( *errResponse.Payload.Detail, fmt.Sprintf( "PPM shipment can't be set to %s because it's not in the %s status.", - models.PPMShipmentStatusNeedsPaymentApproval, + models.PPMShipmentStatusNeedsCloseout, models.PPMShipmentStatusWaitingOnCustomer, ), ) @@ -455,7 +455,7 @@ func (suite *HandlerSuite) TestSubmitPPMShipmentDocumentationHandlerIntegration( suite.NoError(returnedPPMShipment.Validate(strfmt.Default)) suite.EqualUUID(ppmShipment.ID, returnedPPMShipment.ID) - suite.Equal(string(models.PPMShipmentStatusNeedsPaymentApproval), string(returnedPPMShipment.Status)) + suite.Equal(string(models.PPMShipmentStatusNeedsCloseout), string(returnedPPMShipment.Status)) suite.NotNil(returnedPPMShipment.SubmittedAt) suite.NotNil(returnedPPMShipment.SignedCertification) @@ -747,7 +747,7 @@ func (suite *HandlerSuite) TestResubmitPPMShipmentDocumentationHandlerUnit() { _, params := setUpRequestAndParams(ppmShipment, true, true) expectedPPMShipment := ppmShipment - expectedPPMShipment.Status = models.PPMShipmentStatusNeedsPaymentApproval + expectedPPMShipment.Status = models.PPMShipmentStatusNeedsCloseout suite.FatalNotNil(expectedPPMShipment.SubmittedAt) @@ -795,8 +795,8 @@ func (suite *HandlerSuite) TestResubmitPPMShipmentDocumentationHandlerIntegratio var shipmentNeedsResubmitted models.PPMShipment var needsResubmittedSM models.ServiceMember - var shipmentNeedsPaymentApproval models.PPMShipment - var needsPaymentApprovalSM models.ServiceMember + var shipmentNeedsCloseout models.PPMShipment + var needsCloseoutSM models.ServiceMember suite.PreloadData(func() { shipmentNeedsResubmitted = factory.BuildPPMShipmentThatNeedsToBeResubmitted(suite.DB(), userUploader) @@ -804,8 +804,8 @@ func (suite *HandlerSuite) TestResubmitPPMShipmentDocumentationHandlerIntegratio suite.NoError(suite.DB().Save(&shipmentNeedsResubmitted)) needsResubmittedSM = shipmentNeedsResubmitted.Shipment.MoveTaskOrder.Orders.ServiceMember - shipmentNeedsPaymentApproval = factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), nil, nil) - needsPaymentApprovalSM = shipmentNeedsPaymentApproval.Shipment.MoveTaskOrder.Orders.ServiceMember + 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) { @@ -886,7 +886,7 @@ func (suite *HandlerSuite) TestResubmitPPMShipmentDocumentationHandlerIntegratio }) suite.Run("Returns an error if the PPM shipment is not in the right status", func() { - params, handler := setUpParamsAndHandler(shipmentNeedsPaymentApproval, needsPaymentApprovalSM, &internalmessages.SavePPMShipmentSignedCertification{ + params, handler := setUpParamsAndHandler(shipmentNeedsCloseout, needsCloseoutSM, &internalmessages.SavePPMShipmentSignedCertification{ CertificationText: handlers.FmtString("certification text"), Signature: handlers.FmtString("signature"), Date: handlers.FmtDate(time.Now()), @@ -901,7 +901,7 @@ func (suite *HandlerSuite) TestResubmitPPMShipmentDocumentationHandlerIntegratio *errResponse.Payload.Detail, fmt.Sprintf( "PPM shipment can't be set to %s because it's not in the %s status.", - models.PPMShipmentStatusNeedsPaymentApproval, + models.PPMShipmentStatusNeedsCloseout, models.PPMShipmentStatusWaitingOnCustomer, ), ) @@ -928,7 +928,7 @@ func (suite *HandlerSuite) TestResubmitPPMShipmentDocumentationHandlerIntegratio suite.NoError(returnedPPMShipment.Validate(strfmt.Default)) suite.EqualUUID(shipmentNeedsResubmitted.ID, returnedPPMShipment.ID) - suite.Equal(string(models.PPMShipmentStatusNeedsPaymentApproval), string(returnedPPMShipment.Status)) + suite.Equal(string(models.PPMShipmentStatusNeedsCloseout), string(returnedPPMShipment.Status)) if suite.NotNil(returnedPPMShipment.SubmittedAt) { returnedSubmittedAt := handlers.FmtDateTimePtrToPop(returnedPPMShipment.SubmittedAt) diff --git a/pkg/handlers/internalapi/uploads.go b/pkg/handlers/internalapi/uploads.go index e9e67d155a3..503061f05bb 100644 --- a/pkg/handlers/internalapi/uploads.go +++ b/pkg/handlers/internalapi/uploads.go @@ -122,6 +122,17 @@ func (h DeleteUploadHandler) Handle(params uploadop.DeleteUploadParams) middlewa return handlers.ResponseForError(appCtx.Logger(), err), err } + var ppmShipmentStatus models.PPMShipmentStatus + + if params.PpmID != nil { + ppmShipmentId, _ := uuid.FromString(params.PpmID.String()) + ppmShipment, err := models.FetchPPMShipmentByPPMShipmentID(appCtx.DB(), ppmShipmentId) + if err != nil { + return handlers.ResponseForError(appCtx.Logger(), err), err + } + ppmShipmentStatus = ppmShipment.Status + } + if params.OrderID != nil { orderID, _ := uuid.FromString(params.OrderID.String()) move, e := models.FetchMoveByOrderID(appCtx.DB(), orderID) @@ -157,8 +168,8 @@ func (h DeleteUploadHandler) Handle(params uploadop.DeleteUploadParams) middlewa appCtx.Logger().Error("error retrieving move associated with this upload", zap.Error(err)) } - //If move status is not DRAFT, upload cannot be deleted - if *uploadInformation.MoveStatus != models.MoveStatusDRAFT { + //If move status is not DRAFT and customer is not uploading ppm docs, upload cannot be deleted + if (*uploadInformation.MoveStatus != models.MoveStatusDRAFT) && (ppmShipmentStatus != models.PPMShipmentStatusWaitingOnCustomer) { return uploadop.NewDeleteUploadForbidden(), fmt.Errorf("deletion not permitted Move is not in 'DRAFT' status") } diff --git a/pkg/handlers/primeapi/api.go b/pkg/handlers/primeapi/api.go index fc8ef352b24..3950c033ebb 100644 --- a/pkg/handlers/primeapi/api.go +++ b/pkg/handlers/primeapi/api.go @@ -92,7 +92,7 @@ func NewPrimeAPI(handlerConfig handlers.HandlerConfig) *primeoperations.MymoveAP primeAPI.MtoServiceItemCreateMTOServiceItemHandler = CreateMTOServiceItemHandler{ handlerConfig, - mtoserviceitem.NewMTOServiceItemCreator(handlerConfig.HHGPlanner(), builder, moveRouter), + mtoserviceitem.NewMTOServiceItemCreator(handlerConfig.HHGPlanner(), builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), movetaskorder.NewMoveTaskOrderChecker(), } @@ -126,7 +126,7 @@ func NewPrimeAPI(handlerConfig handlers.HandlerConfig) *primeoperations.MymoveAP ) moveTaskOrderUpdater := movetaskorder.NewMoveTaskOrderUpdater( queryBuilder, - mtoserviceitem.NewMTOServiceItemCreator(handlerConfig.HHGPlanner(), queryBuilder, moveRouter), + mtoserviceitem.NewMTOServiceItemCreator(handlerConfig.HHGPlanner(), queryBuilder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), moveRouter, ) ppmEstimator := ppmshipment.NewEstimatePPM(handlerConfig.DTODPlanner(), &paymentrequesthelper.RequestPaymentHelper{}) @@ -161,7 +161,7 @@ func NewPrimeAPI(handlerConfig handlers.HandlerConfig) *primeoperations.MymoveAP fetch.NewFetcher(queryBuilder), movetaskorder.NewMoveTaskOrderUpdater( queryBuilder, - mtoserviceitem.NewMTOServiceItemCreator(handlerConfig.HHGPlanner(), queryBuilder, moveRouter), + mtoserviceitem.NewMTOServiceItemCreator(handlerConfig.HHGPlanner(), queryBuilder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), moveRouter, ), movetaskorder.NewMoveTaskOrderChecker(), @@ -198,7 +198,7 @@ func NewPrimeAPI(handlerConfig handlers.HandlerConfig) *primeoperations.MymoveAP handlerConfig, mtoshipment.NewPrimeMTOShipmentUpdater(builder, fetcher, handlerConfig.HHGPlanner(), moveRouter, moveWeights, handlerConfig.NotificationSender(), paymentRequestShipmentRecalculator, addressUpdater, addressCreator), mtoshipment.NewMTOShipmentStatusUpdater(queryBuilder, - mtoserviceitem.NewMTOServiceItemCreator(handlerConfig.HHGPlanner(), queryBuilder, moveRouter), handlerConfig.HHGPlanner()), + mtoserviceitem.NewMTOServiceItemCreator(handlerConfig.HHGPlanner(), queryBuilder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), handlerConfig.HHGPlanner()), } primeAPI.MtoShipmentUpdateReweighHandler = UpdateReweighHandler{ diff --git a/pkg/handlers/primeapi/move_task_order_test.go b/pkg/handlers/primeapi/move_task_order_test.go index 4597fe652a9..84a368254ab 100644 --- a/pkg/handlers/primeapi/move_task_order_test.go +++ b/pkg/handlers/primeapi/move_task_order_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/fetch" + "github.com/transcom/mymove/pkg/services/ghcrateengine" "github.com/transcom/mymove/pkg/services/mocks" moverouter "github.com/transcom/mymove/pkg/services/move" movetaskorder "github.com/transcom/mymove/pkg/services/move_task_order" @@ -1698,7 +1699,7 @@ func (suite *HandlerSuite) TestUpdateMTOPostCounselingInfo() { mock.Anything, mock.Anything, ).Return(400, nil) - siCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter) + siCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) updater := movetaskorder.NewMoveTaskOrderUpdater(queryBuilder, siCreator, moveRouter) mtoChecker := movetaskorder.NewMoveTaskOrderChecker() @@ -1755,7 +1756,7 @@ func (suite *HandlerSuite) TestUpdateMTOPostCounselingInfo() { mock.Anything, mock.Anything, ).Return(400, nil) - siCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter) + siCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) updater := movetaskorder.NewMoveTaskOrderUpdater(queryBuilder, siCreator, moveRouter) handler := UpdateMTOPostCounselingInformationHandler{ suite.HandlerConfig(), diff --git a/pkg/handlers/primeapi/mto_service_item_test.go b/pkg/handlers/primeapi/mto_service_item_test.go index 1b3797985e0..e3c6aad0947 100644 --- a/pkg/handlers/primeapi/mto_service_item_test.go +++ b/pkg/handlers/primeapi/mto_service_item_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/address" + "github.com/transcom/mymove/pkg/services/ghcrateengine" "github.com/transcom/mymove/pkg/services/mocks" moverouter "github.com/transcom/mymove/pkg/services/move" movetaskorder "github.com/transcom/mymove/pkg/services/move_task_order" @@ -92,7 +93,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -150,7 +151,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -288,7 +289,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -332,7 +333,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -483,7 +484,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemDomesticCratingHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -520,7 +521,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemDomesticCratingHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -643,7 +644,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemOriginSITHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -689,7 +690,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemOriginSITHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -758,7 +759,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemOriginSITHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -842,7 +843,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemOriginSITHandlerWithDOFSITNoA mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -952,7 +953,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemOriginSITHandlerWithDOFSITWit mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -1125,7 +1126,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemDestSITHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -1199,7 +1200,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemDestSITHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -1232,7 +1233,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemDestSITHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -1288,7 +1289,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemDestSITHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -1352,7 +1353,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemDestSITHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -1383,7 +1384,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemDestSITHandler() { subtestData.mtoServiceItem.ReService.Code = models.ReServiceCodeDDDSIT moveRouter := moverouter.NewMoveRouter() planner := &routemocks.Planner{} - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, diff --git a/pkg/handlers/primeapi/mto_shipment_test.go b/pkg/handlers/primeapi/mto_shipment_test.go index d40102df4d7..13904aaf2c3 100644 --- a/pkg/handlers/primeapi/mto_shipment_test.go +++ b/pkg/handlers/primeapi/mto_shipment_test.go @@ -57,7 +57,7 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandler() { ).Return(400, nil) moveTaskOrderUpdater := movetaskorder.NewMoveTaskOrderUpdater( builder, - mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter), + mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), moveRouter, ) shipmentCreator := shipmentorchestrator.NewShipmentCreator(mtoShipmentCreator, ppmShipmentCreator, shipmentRouter, moveTaskOrderUpdater) @@ -2352,7 +2352,7 @@ func (suite *HandlerSuite) TestUpdateMTOShipmentStatusHandler() { handlerConfig, mtoshipment.NewPrimeMTOShipmentUpdater(builder, fetcher, planner, moveRouter, moveWeights, suite.TestNotificationSender(), paymentRequestShipmentRecalculator, addressUpdater, addressCreator), mtoshipment.NewMTOShipmentStatusUpdater(builder, - mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter), planner), + mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), planner), } // Set up Prime-available move @@ -2541,7 +2541,7 @@ func (suite *HandlerSuite) TestDeleteMTOShipmentHandler() { ).Return(400, nil) moveTaskOrderUpdater := movetaskorder.NewMoveTaskOrderUpdater( builder, - mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter), + mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), moveRouter, ) deleter := mtoshipment.NewPrimeShipmentDeleter(moveTaskOrderUpdater) diff --git a/pkg/handlers/primeapi/payloads/payload_to_model.go b/pkg/handlers/primeapi/payloads/payload_to_model.go index 246f5d13493..8dd4ef8a78e 100644 --- a/pkg/handlers/primeapi/payloads/payload_to_model.go +++ b/pkg/handlers/primeapi/payloads/payload_to_model.go @@ -266,6 +266,16 @@ func MTOShipmentModelFromUpdate(mtoShipment *primemessages.UpdateMTOShipment, mt CounselorRemarks: mtoShipment.CounselorRemarks, } + if mtoShipment.ActualProGearWeight != nil { + actualProGearWeight := unit.Pound(*mtoShipment.ActualProGearWeight) + model.ActualProGearWeight = &actualProGearWeight + } + + if mtoShipment.ActualSpouseProGearWeight != nil { + actualSpouseProGearWeight := unit.Pound(*mtoShipment.ActualSpouseProGearWeight) + model.ActualSpouseProGearWeight = &actualSpouseProGearWeight + } + if mtoShipment.PrimeActualWeight != nil { actualWeight := unit.Pound(*mtoShipment.PrimeActualWeight) model.PrimeActualWeight = &actualWeight diff --git a/pkg/handlers/primeapiv2/api.go b/pkg/handlers/primeapiv2/api.go index 7721fc8d42f..a003585ac35 100644 --- a/pkg/handlers/primeapiv2/api.go +++ b/pkg/handlers/primeapiv2/api.go @@ -46,7 +46,7 @@ func NewPrimeAPI(handlerConfig handlers.HandlerConfig) *primev2operations.Mymove moveTaskOrderUpdater := movetaskorder.NewMoveTaskOrderUpdater( queryBuilder, - mtoserviceitem.NewMTOServiceItemCreator(handlerConfig.HHGPlanner(), queryBuilder, moveRouter), + mtoserviceitem.NewMTOServiceItemCreator(handlerConfig.HHGPlanner(), queryBuilder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), moveRouter, ) ppmEstimator := ppmshipment.NewEstimatePPM(handlerConfig.DTODPlanner(), &paymentrequesthelper.RequestPaymentHelper{}) diff --git a/pkg/handlers/primeapiv2/mto_service_item_test.go b/pkg/handlers/primeapiv2/mto_service_item_test.go index e25cc9e3577..01cc27a7793 100644 --- a/pkg/handlers/primeapiv2/mto_service_item_test.go +++ b/pkg/handlers/primeapiv2/mto_service_item_test.go @@ -19,6 +19,7 @@ import ( "github.com/transcom/mymove/pkg/handlers/primeapi/payloads" "github.com/transcom/mymove/pkg/models" routemocks "github.com/transcom/mymove/pkg/route/mocks" + "github.com/transcom/mymove/pkg/services/ghcrateengine" "github.com/transcom/mymove/pkg/services/mocks" moverouter "github.com/transcom/mymove/pkg/services/move" movetaskorder "github.com/transcom/mymove/pkg/services/move_task_order" @@ -88,7 +89,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -146,7 +147,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -284,7 +285,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -328,7 +329,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -479,7 +480,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemDomesticCratingHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -516,7 +517,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemDomesticCratingHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -639,7 +640,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemOriginSITHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -685,7 +686,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemOriginSITHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -754,7 +755,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemOriginSITHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -838,7 +839,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemOriginSITHandlerWithDOFSITNoA mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -946,7 +947,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemOriginSITHandlerWithDOFSITWit mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -1113,7 +1114,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemDestSITHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -1187,7 +1188,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemDestSITHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -1220,7 +1221,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemDestSITHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -1276,7 +1277,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemDestSITHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -1340,7 +1341,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemDestSITHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -1371,7 +1372,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemDestSITHandler() { subtestData.mtoServiceItem.ReService.Code = models.ReServiceCodeDDDSIT moveRouter := moverouter.NewMoveRouter() planner := &routemocks.Planner{} - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, diff --git a/pkg/handlers/primeapiv2/mto_shipment_test.go b/pkg/handlers/primeapiv2/mto_shipment_test.go index f3cd3ca0ad5..4e96821c9ed 100644 --- a/pkg/handlers/primeapiv2/mto_shipment_test.go +++ b/pkg/handlers/primeapiv2/mto_shipment_test.go @@ -19,6 +19,7 @@ import ( routemocks "github.com/transcom/mymove/pkg/route/mocks" "github.com/transcom/mymove/pkg/services/address" "github.com/transcom/mymove/pkg/services/fetch" + "github.com/transcom/mymove/pkg/services/ghcrateengine" "github.com/transcom/mymove/pkg/services/mocks" moveservices "github.com/transcom/mymove/pkg/services/move" movetaskorder "github.com/transcom/mymove/pkg/services/move_task_order" @@ -49,7 +50,7 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandler() { ).Return(400, nil) moveTaskOrderUpdater := movetaskorder.NewMoveTaskOrderUpdater( builder, - mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter), + mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), moveRouter, ) shipmentCreator := shipmentorchestrator.NewShipmentCreator(mtoShipmentCreator, ppmShipmentCreator, shipmentRouter, moveTaskOrderUpdater) diff --git a/pkg/handlers/primeapiv2/payloads/payload_to_model.go b/pkg/handlers/primeapiv2/payloads/payload_to_model.go index 1c753a2de09..a023512eb64 100644 --- a/pkg/handlers/primeapiv2/payloads/payload_to_model.go +++ b/pkg/handlers/primeapiv2/payloads/payload_to_model.go @@ -276,6 +276,16 @@ func MTOShipmentModelFromUpdate(mtoShipment *primev2messages.UpdateMTOShipment, ActualSpouseProGearWeight: handlers.PoundPtrFromInt64Ptr(mtoShipment.ActualSpouseProGearWeight), } + if mtoShipment.ActualProGearWeight != nil { + actualProGearWeight := unit.Pound(*mtoShipment.ActualProGearWeight) + model.ActualProGearWeight = &actualProGearWeight + } + + if mtoShipment.ActualSpouseProGearWeight != nil { + actualSpouseProGearWeight := unit.Pound(*mtoShipment.ActualSpouseProGearWeight) + model.ActualSpouseProGearWeight = &actualSpouseProGearWeight + } + if mtoShipment.PrimeActualWeight != nil { actualWeight := unit.Pound(*mtoShipment.PrimeActualWeight) model.PrimeActualWeight = &actualWeight diff --git a/pkg/handlers/primeapiv3/api.go b/pkg/handlers/primeapiv3/api.go index 433eabb1f3d..39592cd153d 100644 --- a/pkg/handlers/primeapiv3/api.go +++ b/pkg/handlers/primeapiv3/api.go @@ -47,7 +47,7 @@ func NewPrimeAPI(handlerConfig handlers.HandlerConfig) *primev3operations.Mymove moveTaskOrderUpdater := movetaskorder.NewMoveTaskOrderUpdater( queryBuilder, - mtoserviceitem.NewMTOServiceItemCreator(handlerConfig.HHGPlanner(), queryBuilder, moveRouter), + mtoserviceitem.NewMTOServiceItemCreator(handlerConfig.HHGPlanner(), queryBuilder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), moveRouter, ) ppmEstimator := ppmshipment.NewEstimatePPM(handlerConfig.DTODPlanner(), &paymentrequesthelper.RequestPaymentHelper{}) diff --git a/pkg/handlers/primeapiv3/mto_service_item_test.go b/pkg/handlers/primeapiv3/mto_service_item_test.go index 97ccd992a8c..04b81f6c6d2 100644 --- a/pkg/handlers/primeapiv3/mto_service_item_test.go +++ b/pkg/handlers/primeapiv3/mto_service_item_test.go @@ -19,6 +19,7 @@ import ( "github.com/transcom/mymove/pkg/handlers/primeapi/payloads" "github.com/transcom/mymove/pkg/models" routemocks "github.com/transcom/mymove/pkg/route/mocks" + "github.com/transcom/mymove/pkg/services/ghcrateengine" "github.com/transcom/mymove/pkg/services/mocks" moverouter "github.com/transcom/mymove/pkg/services/move" movetaskorder "github.com/transcom/mymove/pkg/services/move_task_order" @@ -88,7 +89,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemHandler() { ).Return(400, nil) subtestData := makeSubtestData() moveRouter := moverouter.NewMoveRouter() - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -146,7 +147,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -284,7 +285,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -328,7 +329,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -479,7 +480,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemDomesticCratingHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -516,7 +517,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemDomesticCratingHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -639,7 +640,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemOriginSITHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -685,7 +686,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemOriginSITHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -754,7 +755,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemOriginSITHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -838,7 +839,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemOriginSITHandlerWithDOFSITNoA mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -946,7 +947,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemOriginSITHandlerWithDOFSITWit mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -1113,7 +1114,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemDestSITHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -1187,7 +1188,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemDestSITHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -1220,7 +1221,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemDestSITHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -1276,7 +1277,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemDestSITHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -1340,7 +1341,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemDestSITHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, @@ -1376,7 +1377,7 @@ func (suite *HandlerSuite) TestCreateMTOServiceItemDestSITHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := CreateMTOServiceItemHandler{ suite.HandlerConfig(), creator, diff --git a/pkg/handlers/primeapiv3/mto_shipment_test.go b/pkg/handlers/primeapiv3/mto_shipment_test.go index fb665ec873d..e652a276d2b 100644 --- a/pkg/handlers/primeapiv3/mto_shipment_test.go +++ b/pkg/handlers/primeapiv3/mto_shipment_test.go @@ -54,7 +54,7 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandler() { ).Return(400, nil) moveTaskOrderUpdater := movetaskorder.NewMoveTaskOrderUpdater( builder, - mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter), + mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), moveRouter, ) shipmentCreator := shipmentorchestrator.NewShipmentCreator(mtoShipmentCreator, ppmShipmentCreator, shipmentRouter, moveTaskOrderUpdater) diff --git a/pkg/handlers/primeapiv3/payloads/payload_to_model.go b/pkg/handlers/primeapiv3/payloads/payload_to_model.go index fd6f7968cc3..abdec21acb8 100644 --- a/pkg/handlers/primeapiv3/payloads/payload_to_model.go +++ b/pkg/handlers/primeapiv3/payloads/payload_to_model.go @@ -302,6 +302,16 @@ func MTOShipmentModelFromUpdate(mtoShipment *primev3messages.UpdateMTOShipment, CounselorRemarks: mtoShipment.CounselorRemarks, } + if mtoShipment.ActualProGearWeight != nil { + actualProGearWeight := unit.Pound(*mtoShipment.ActualProGearWeight) + model.ActualProGearWeight = &actualProGearWeight + } + + if mtoShipment.ActualSpouseProGearWeight != nil { + actualSpouseProGearWeight := unit.Pound(*mtoShipment.ActualSpouseProGearWeight) + model.ActualSpouseProGearWeight = &actualSpouseProGearWeight + } + if mtoShipment.PrimeActualWeight != nil { actualWeight := unit.Pound(*mtoShipment.PrimeActualWeight) model.PrimeActualWeight = &actualWeight diff --git a/pkg/handlers/supportapi/api.go b/pkg/handlers/supportapi/api.go index a52c097e20f..ce516422f38 100644 --- a/pkg/handlers/supportapi/api.go +++ b/pkg/handlers/supportapi/api.go @@ -47,7 +47,7 @@ func NewSupportAPIHandler(handlerConfig handlers.HandlerConfig) http.Handler { handlerConfig, movetaskorder.NewMoveTaskOrderUpdater( queryBuilder, - mtoserviceitem.NewMTOServiceItemCreator(handlerConfig.HHGPlanner(), queryBuilder, moveRouter), + mtoserviceitem.NewMTOServiceItemCreator(handlerConfig.HHGPlanner(), queryBuilder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), moveRouter, ), } @@ -80,7 +80,7 @@ func NewSupportAPIHandler(handlerConfig handlers.HandlerConfig) http.Handler { handlerConfig, fetch.NewFetcher(queryBuilder), mtoshipment.NewMTOShipmentStatusUpdater(queryBuilder, - mtoserviceitem.NewMTOServiceItemCreator(handlerConfig.HHGPlanner(), queryBuilder, moveRouter), handlerConfig.HHGPlanner()), + mtoserviceitem.NewMTOServiceItemCreator(handlerConfig.HHGPlanner(), queryBuilder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), handlerConfig.HHGPlanner()), } supportAPI.MtoServiceItemUpdateMTOServiceItemStatusHandler = UpdateMTOServiceItemStatusHandler{handlerConfig, mtoserviceitem.NewMTOServiceItemUpdater(handlerConfig.HHGPlanner(), queryBuilder, moveRouter, shipmentFetcher, addressCreator)} diff --git a/pkg/handlers/supportapi/move_task_order_test.go b/pkg/handlers/supportapi/move_task_order_test.go index 22b085b19b5..548999ecc69 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/ghcrateengine" "github.com/transcom/mymove/pkg/services/mocks" moverouter "github.com/transcom/mymove/pkg/services/move" movetaskorder "github.com/transcom/mymove/pkg/services/move_task_order" @@ -173,7 +174,7 @@ func (suite *HandlerSuite) TestMakeMoveAvailableHandlerIntegrationSuccess() { mock.Anything, mock.Anything, ).Return(400, nil) - siCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter) + siCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) // make the request handler := MakeMoveTaskOrderAvailableHandlerFunc{handlerConfig, @@ -361,7 +362,7 @@ func (suite *HandlerSuite) TestCreateMoveTaskOrderRequestHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - siCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter) + siCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) // Submit the request to approve the MTO approvalHandler := MakeMoveTaskOrderAvailableHandlerFunc{ diff --git a/pkg/handlers/supportapi/mto_shipment_test.go b/pkg/handlers/supportapi/mto_shipment_test.go index 10252d19680..f42dd8954a1 100644 --- a/pkg/handlers/supportapi/mto_shipment_test.go +++ b/pkg/handlers/supportapi/mto_shipment_test.go @@ -17,6 +17,7 @@ import ( "github.com/transcom/mymove/pkg/models" routemocks "github.com/transcom/mymove/pkg/route/mocks" "github.com/transcom/mymove/pkg/services/fetch" + "github.com/transcom/mymove/pkg/services/ghcrateengine" "github.com/transcom/mymove/pkg/services/mocks" moverouter "github.com/transcom/mymove/pkg/services/move" mtoserviceitem "github.com/transcom/mymove/pkg/services/mto_service_item" @@ -97,7 +98,7 @@ func (suite *HandlerSuite) TestUpdateMTOShipmentStatusHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - siCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter) + siCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) planner.On("Zip5TransitDistanceLineHaul", mock.AnythingOfType("*appcontext.appContext"), mock.Anything, diff --git a/pkg/models/application_parameters.go b/pkg/models/application_parameters.go index ddcb2940ffb..dccf21fd10f 100644 --- a/pkg/models/application_parameters.go +++ b/pkg/models/application_parameters.go @@ -36,3 +36,18 @@ func FetchParameterValue(db *pop.Connection, param string, value string) (Applic return parameter, nil } + +// FetchParameterValue returns a specific parameter value from the db +func FetchParameterValueByName(db *pop.Connection, param string) (ApplicationParameters, error) { + var parameter ApplicationParameters + err := db.Q().Where(`parameter_name=$1`, param).First(¶meter) + // if it isn't found, we'll return an empty object + if err != nil { + if errors.Cause(err).Error() == RecordNotFoundErrorString { + return ApplicationParameters{}, nil + } + return ApplicationParameters{}, err + } + + return parameter, nil +} diff --git a/pkg/models/moving_expense.go b/pkg/models/moving_expense.go index d48bbb2137e..e5e3acc8ec5 100644 --- a/pkg/models/moving_expense.go +++ b/pkg/models/moving_expense.go @@ -45,24 +45,30 @@ var AllowedExpenseTypes = []string{ } type MovingExpense struct { - ID uuid.UUID `json:"id" db:"id"` - PPMShipmentID uuid.UUID `json:"ppm_shipment_id" db:"ppm_shipment_id"` - PPMShipment PPMShipment `belongs_to:"ppm_shipments" fk_id:"ppm_shipment_id"` - DocumentID uuid.UUID `json:"document_id" db:"document_id"` - Document Document `belongs_to:"documents" fk_id:"document_id"` - CreatedAt time.Time `json:"created_at" db:"created_at"` - UpdatedAt time.Time `json:"updated_at" db:"updated_at"` - DeletedAt *time.Time `json:"deleted_at" db:"deleted_at"` - MovingExpenseType *MovingExpenseReceiptType `json:"moving_expense_type" db:"moving_expense_type"` - Description *string `json:"description" db:"description"` - PaidWithGTCC *bool `json:"paid_with_gtcc" db:"paid_with_gtcc"` - Amount *unit.Cents `json:"amount" db:"amount"` - MissingReceipt *bool `json:"missing_receipt" db:"missing_receipt"` - Status *PPMDocumentStatus `json:"status" db:"status"` - Reason *string `json:"reason" db:"reason"` - SITStartDate *time.Time `json:"sit_start_date" db:"sit_start_date"` - SITEndDate *time.Time `json:"sit_end_date" db:"sit_end_date"` - WeightStored *unit.Pound `json:"weight_stored" db:"weight_stored"` + ID uuid.UUID `json:"id" db:"id"` + PPMShipmentID uuid.UUID `json:"ppm_shipment_id" db:"ppm_shipment_id"` + PPMShipment PPMShipment `belongs_to:"ppm_shipments" fk_id:"ppm_shipment_id"` + DocumentID uuid.UUID `json:"document_id" db:"document_id"` + Document Document `belongs_to:"documents" fk_id:"document_id"` + CreatedAt time.Time `json:"created_at" db:"created_at"` + UpdatedAt time.Time `json:"updated_at" db:"updated_at"` + DeletedAt *time.Time `json:"deleted_at" db:"deleted_at"` + MovingExpenseType *MovingExpenseReceiptType `json:"moving_expense_type" db:"moving_expense_type"` + SubmittedMovingExpenseType *MovingExpenseReceiptType `json:"submitted_moving_expense_type" db:"submitted_moving_expense_type"` + Description *string `json:"description" db:"description"` + SubmittedDescription *string `json:"submitted_description" db:"submitted_description"` + PaidWithGTCC *bool `json:"paid_with_gtcc" db:"paid_with_gtcc"` + Amount *unit.Cents `json:"amount" db:"amount"` + SubmittedAmount *unit.Cents `json:"submitted_amount" db:"submitted_amount"` + MissingReceipt *bool `json:"missing_receipt" db:"missing_receipt"` + Status *PPMDocumentStatus `json:"status" db:"status"` + Reason *string `json:"reason" db:"reason"` + SITStartDate *time.Time `json:"sit_start_date" db:"sit_start_date"` + SubmittedSITStartDate *time.Time `json:"submitted_sit_start_date" db:"submitted_sit_start_date"` + SITEndDate *time.Time `json:"sit_end_date" db:"sit_end_date"` + SubmittedSITEndDate *time.Time `json:"submitted_sit_end_date" db:"submitted_sit_end_date"` + WeightStored *unit.Pound `json:"weight_stored" db:"weight_stored"` + SITLocation *SITLocationType `json:"sit_location" db:"sit_location"` } // TableName overrides the table name used by Pop. diff --git a/pkg/models/mto_service_items.go b/pkg/models/mto_service_items.go index fba3dce20f2..4f3dac57a1e 100644 --- a/pkg/models/mto_service_items.go +++ b/pkg/models/mto_service_items.go @@ -65,7 +65,7 @@ type MTOServiceItem struct { CustomerExpense bool `db:"customer_expense"` CustomerExpenseReason *string `db:"customer_expense_reason"` SITDeliveryMiles *int `db:"sit_delivery_miles"` - PricingEstimate *int `db:"pricing_estimate"` + PricingEstimate *unit.Cents `db:"pricing_estimate"` StandaloneCrate *bool `db:"standalone_crate"` } @@ -98,6 +98,7 @@ type MTOServiceItemSingle struct { CustomerExpense bool `db:"customer_expense"` CustomerExpenseReason *string `db:"customer_expense_reason"` SITDeliveryMiles *unit.Miles `db:"sit_delivery_miles"` + PricingEstimate *unit.Cents `db:"pricing_estimate"` } // TableName overrides the table name used by Pop. diff --git a/pkg/models/ppm_shipment.go b/pkg/models/ppm_shipment.go index 2335b0750bd..ef95ef4562a 100644 --- a/pkg/models/ppm_shipment.go +++ b/pkg/models/ppm_shipment.go @@ -60,10 +60,10 @@ const ( PPMShipmentStatusWaitingOnCustomer PPMShipmentStatus = "WAITING_ON_CUSTOMER" // PPMShipmentStatusNeedsAdvanceApproval captures enum value "NEEDS_ADVANCE_APPROVAL" PPMShipmentStatusNeedsAdvanceApproval PPMShipmentStatus = "NEEDS_ADVANCE_APPROVAL" - // PPMShipmentStatusNeedsPaymentApproval captures enum value "NEEDS_PAYMENT_APPROVAL" - PPMShipmentStatusNeedsPaymentApproval PPMShipmentStatus = "NEEDS_PAYMENT_APPROVAL" - // PPMShipmentStatusPaymentApproved captures enum value "PAYMENT_APPROVED" - PPMShipmentStatusPaymentApproved PPMShipmentStatus = "PAYMENT_APPROVED" + // PPMShipmentStatusNeedsCloseout captures enum value "NEEDS_CLOSEOUT" + PPMShipmentStatusNeedsCloseout PPMShipmentStatus = "NEEDS_CLOSEOUT" + // PPMShipmentStatusCloseoutComplete captures enum value "CLOSEOUT_COMPLETE" + PPMShipmentStatusCloseoutComplete PPMShipmentStatus = "CLOSEOUT_COMPLETE" // PPMStatusCOMPLETED captures enum value "COMPLETED" PPMShipmentStatusComplete PPMShipmentStatus = "COMPLETED" ) @@ -76,8 +76,8 @@ var AllowedPPMShipmentStatuses = []string{ string(PPMShipmentStatusSubmitted), string(PPMShipmentStatusWaitingOnCustomer), string(PPMShipmentStatusNeedsAdvanceApproval), - string(PPMShipmentStatusNeedsPaymentApproval), - string(PPMShipmentStatusPaymentApproved), + string(PPMShipmentStatusNeedsCloseout), + string(PPMShipmentStatusCloseoutComplete), } // PPMAdvanceStatus represents the status of an advance that can be approved, edited or rejected by a SC diff --git a/pkg/models/progear_weight_ticket.go b/pkg/models/progear_weight_ticket.go index 09c859aa490..c191a832d5a 100644 --- a/pkg/models/progear_weight_ticket.go +++ b/pkg/models/progear_weight_ticket.go @@ -12,20 +12,23 @@ import ( ) type ProgearWeightTicket struct { - ID uuid.UUID `json:"id" db:"id"` - PPMShipmentID uuid.UUID `json:"ppm_shipment_id" db:"ppm_shipment_id"` - PPMShipment PPMShipment `belongs_to:"ppm_shipments" fk_id:"ppm_shipment_id"` - BelongsToSelf *bool `json:"belongs_to_self" db:"belongs_to_self"` - Description *string `json:"description" db:"description"` - HasWeightTickets *bool `json:"has_weight_tickets" db:"has_weight_tickets"` - Weight *unit.Pound `json:"weight" db:"weight"` - DocumentID uuid.UUID `json:"document_id" db:"document_id"` - Document Document `belongs_to:"documents" fk_id:"document_id"` - Status *PPMDocumentStatus `json:"status" db:"status"` - Reason *string `json:"reason" db:"reason"` - CreatedAt time.Time `json:"created_at" db:"created_at"` - UpdatedAt time.Time `json:"updated_at" db:"updated_at"` - DeletedAt *time.Time `json:"deleted_at" db:"deleted_at"` + ID uuid.UUID `json:"id" db:"id"` + PPMShipmentID uuid.UUID `json:"ppm_shipment_id" db:"ppm_shipment_id"` + PPMShipment PPMShipment `belongs_to:"ppm_shipments" fk_id:"ppm_shipment_id"` + BelongsToSelf *bool `json:"belongs_to_self" db:"belongs_to_self"` + SubmittedBelongsToSelf *bool `json:"submitted_belongs_to_self" db:"submitted_belongs_to_self"` + Description *string `json:"description" db:"description"` + HasWeightTickets *bool `json:"has_weight_tickets" db:"has_weight_tickets"` + SubmittedHasWeightTickets *bool `json:"submitted_has_weight_tickets" db:"submitted_has_weight_tickets"` + Weight *unit.Pound `json:"weight" db:"weight"` + SubmittedWeight *unit.Pound `json:"submitted_weight" db:"submitted_weight"` + DocumentID uuid.UUID `json:"document_id" db:"document_id"` + Document Document `belongs_to:"documents" fk_id:"document_id"` + Status *PPMDocumentStatus `json:"status" db:"status"` + Reason *string `json:"reason" db:"reason"` + CreatedAt time.Time `json:"created_at" db:"created_at"` + UpdatedAt time.Time `json:"updated_at" db:"updated_at"` + DeletedAt *time.Time `json:"deleted_at" db:"deleted_at"` } // TableName overrides the table name used by Pop. diff --git a/pkg/models/roles/roles.go b/pkg/models/roles/roles.go index 1fbb5e60eb4..3e1c68a05ec 100644 --- a/pkg/models/roles/roles.go +++ b/pkg/models/roles/roles.go @@ -28,8 +28,10 @@ const ( RoleTypeServicesCounselor RoleType = "services_counselor" // RoleTypePrimeSimulator is the PrimeSimulator Role RoleTypePrimeSimulator RoleType = "prime_simulator" - // RoleTypeQaeCsr is the Quality Assurance and Customer Support Role - RoleTypeQaeCsr RoleType = "qae_csr" + // RoleTypeQae is the Quality Assurance Evaluator Role + RoleTypeQae RoleType = "qae" + // RoleTypeCustomerServiceRepresentative is the Customer Support Representative Role + RoleTypeCustomerServiceRepresentative RoleType = "customer_service_representative" // RoleTypePrime is the Role associated with actions performed by the Prime RoleTypePrime RoleType = "prime" ) diff --git a/pkg/models/service_item_param_key.go b/pkg/models/service_item_param_key.go index 3e2dbb687df..6a708cb8f94 100644 --- a/pkg/models/service_item_param_key.go +++ b/pkg/models/service_item_param_key.go @@ -149,6 +149,12 @@ const ( ServiceItemParamNameZipSITOriginHHGActualAddress ServiceItemParamName = "ZipSITOriginHHGActualAddress" // ServiceItemParamNameZipSITOriginHHGOriginalAddress is the param key name ZipSITOriginHHGOriginalAddress ServiceItemParamNameZipSITOriginHHGOriginalAddress ServiceItemParamName = "ZipSITOriginHHGOriginalAddress" + // ServiceItemParamNameStandaloneCrate is the param key name StandaloneCrate + ServiceItemParamNameStandaloneCrate ServiceItemParamName = "StandaloneCrate" + // ServiceItemParamNameStandaloneCrateCap is the param key name StandaloneCrateCap + ServiceItemParamNameStandaloneCrateCap ServiceItemParamName = "StandaloneCrateCap" + // ServiceItemParamNameUncappedRequestTotal is the param key name UncappedRequestTotal + ServiceItemParamNameUncappedRequestTotal ServiceItemParamName = "UncappedRequestTotal" ) // ServiceItemParamType is a type of service item parameter @@ -263,6 +269,9 @@ var ValidServiceItemParamNames = []ServiceItemParamName{ ServiceItemParamNameZipSITDestHHGOriginalAddress, ServiceItemParamNameZipSITOriginHHGActualAddress, ServiceItemParamNameZipSITOriginHHGOriginalAddress, + ServiceItemParamNameStandaloneCrate, + ServiceItemParamNameStandaloneCrateCap, + ServiceItemParamNameUncappedRequestTotal, } // ValidServiceItemParamNameStrings lists all valid service item param key names @@ -333,6 +342,9 @@ var ValidServiceItemParamNameStrings = []string{ string(ServiceItemParamNameZipSITDestHHGOriginalAddress), string(ServiceItemParamNameZipSITOriginHHGActualAddress), string(ServiceItemParamNameZipSITOriginHHGOriginalAddress), + string(ServiceItemParamNameStandaloneCrate), + string(ServiceItemParamNameStandaloneCrateCap), + string(ServiceItemParamNameUncappedRequestTotal), } // ValidServiceItemParamTypes lists all valid service item param types diff --git a/pkg/models/weight_ticket.go b/pkg/models/weight_ticket.go index fa17e8802fd..2ca17ebdb9e 100644 --- a/pkg/models/weight_ticket.go +++ b/pkg/models/weight_ticket.go @@ -22,15 +22,19 @@ type WeightTicket struct { DeletedAt *time.Time `json:"deleted_at" db:"deleted_at"` VehicleDescription *string `json:"vehicle_description" db:"vehicle_description"` EmptyWeight *unit.Pound `json:"empty_weight" db:"empty_weight"` + SubmittedEmptyWeight *unit.Pound `json:"submitted_empty_weight" db:"submitted_empty_weight"` MissingEmptyWeightTicket *bool `json:"missing_empty_weight_ticket" db:"missing_empty_weight_ticket"` EmptyDocumentID uuid.UUID `json:"empty_document_id" db:"empty_document_id"` EmptyDocument Document `belongs_to:"documents" fk_id:"empty_document_id"` FullWeight *unit.Pound `json:"full_weight" db:"full_weight"` + SubmittedFullWeight *unit.Pound `json:"submitted_full_weight" db:"submitted_full_weight"` MissingFullWeightTicket *bool `json:"missing_full_weight_ticket" db:"missing_full_weight_ticket"` FullDocumentID uuid.UUID `json:"full_document_id" db:"full_document_id"` FullDocument Document `belongs_to:"documents" fk_id:"full_document_id"` OwnsTrailer *bool `json:"owns_trailer" db:"owns_trailer"` + SubmittedOwnsTrailer *bool `json:"submitted_owns_trailer" db:"submitted_owns_trailer"` TrailerMeetsCriteria *bool `json:"trailer_meets_criteria" db:"trailer_meets_criteria"` + SubmittedTrailerMeetsCriteria *bool `json:"submitted_trailer_meets_criteria" db:"submitted_trailer_meets_criteria"` ProofOfTrailerOwnershipDocumentID uuid.UUID `json:"proof_of_trailer_ownership_document_id" db:"proof_of_trailer_ownership_document_id"` ProofOfTrailerOwnershipDocument Document `belongs_to:"documents" fk_id:"proof_of_trailer_ownership_document_id"` Status *PPMDocumentStatus `json:"status" db:"status"` diff --git a/pkg/payment_request/service_param_value_lookups/service_param_value_lookups.go b/pkg/payment_request/service_param_value_lookups/service_param_value_lookups.go index d12e4cdd598..ad5423510a6 100644 --- a/pkg/payment_request/service_param_value_lookups/service_param_value_lookups.go +++ b/pkg/payment_request/service_param_value_lookups/service_param_value_lookups.go @@ -82,6 +82,8 @@ var ServiceItemParamsWithLookups = []models.ServiceItemParamName{ models.ServiceItemParamNameDimensionHeight, models.ServiceItemParamNameDimensionLength, models.ServiceItemParamNameDimensionWidth, + models.ServiceItemParamNameStandaloneCrate, + models.ServiceItemParamNameStandaloneCrateCap, } // ServiceParamLookupInitialize initializes service parameter lookup @@ -411,6 +413,14 @@ func InitializeLookups(shipment models.MTOShipment, serviceItem models.MTOServic Dimensions: serviceItem.Dimensions, } + lookups[models.ServiceItemParamNameStandaloneCrate] = StandaloneCrateLookup{ + ServiceItem: serviceItem, + } + + lookups[models.ServiceItemParamNameStandaloneCrateCap] = StandaloneCrateCapLookup{ + ServiceItem: serviceItem, + } + return lookups } diff --git a/pkg/payment_request/service_param_value_lookups/standalone_crate_cap_lookup.go b/pkg/payment_request/service_param_value_lookups/standalone_crate_cap_lookup.go new file mode 100644 index 00000000000..a2f17b761ee --- /dev/null +++ b/pkg/payment_request/service_param_value_lookups/standalone_crate_cap_lookup.go @@ -0,0 +1,17 @@ +package serviceparamvaluelookups + +import ( + "github.com/transcom/mymove/pkg/appcontext" + "github.com/transcom/mymove/pkg/models" +) + +// StandaloneCrateCapLookup does lookup on application parameters +type StandaloneCrateCapLookup struct { + ServiceItem models.MTOServiceItem +} + +func (r StandaloneCrateCapLookup) lookup(appCtx appcontext.AppContext, _ *ServiceItemParamKeyData) (string, error) { + applicationParam, _ := models.FetchParameterValueByName(appCtx.DB(), "standaloneCrateCap") + + return *applicationParam.ParameterValue, nil +} diff --git a/pkg/payment_request/service_param_value_lookups/standalone_crate_lookup.go b/pkg/payment_request/service_param_value_lookups/standalone_crate_lookup.go new file mode 100644 index 00000000000..3c209bd01c5 --- /dev/null +++ b/pkg/payment_request/service_param_value_lookups/standalone_crate_lookup.go @@ -0,0 +1,22 @@ +package serviceparamvaluelookups + +import ( + "strconv" + + "github.com/transcom/mymove/pkg/appcontext" + "github.com/transcom/mymove/pkg/models" +) + +// StandaloneCrateLookup does lookup on standaloneCrate +type StandaloneCrateLookup struct { + ServiceItem models.MTOServiceItem +} + +func (r StandaloneCrateLookup) lookup(_ appcontext.AppContext, _ *ServiceItemParamKeyData) (string, error) { + standaloneCrate := r.ServiceItem.StandaloneCrate + if standaloneCrate == nil { + return "false", nil + } + + return strconv.FormatBool(*standaloneCrate), nil +} diff --git a/pkg/services/evaluation_report/evaluation_report_fetcher_test.go b/pkg/services/evaluation_report/evaluation_report_fetcher_test.go index 32c82f50fc3..2c95cca7156 100644 --- a/pkg/services/evaluation_report/evaluation_report_fetcher_test.go +++ b/pkg/services/evaluation_report/evaluation_report_fetcher_test.go @@ -203,7 +203,7 @@ func (suite *EvaluationReportSuite) TestFetchEvaluationReportByID() { // successful fetch suite.Run("fetch for a submitted evaluation report that exists should be successful", func() { fetcher := NewEvaluationReportFetcher() - officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeQaeCsr}) + officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeQae}) report := factory.BuildEvaluationReport(suite.DB(), []factory.Customization{ { Model: officeUser, @@ -223,8 +223,8 @@ func (suite *EvaluationReportSuite) TestFetchEvaluationReportByID() { // forbidden if they don't own the draft suite.Run("fetch for a draft evaluation report should return a forbidden if the requester isn't the owner", func() { fetcher := NewEvaluationReportFetcher() - officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeQaeCsr}) - officeUserOwner := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeQaeCsr}) + officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeQae}) + officeUserOwner := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeQae}) report := factory.BuildEvaluationReport(suite.DB(), []factory.Customization{ { Model: officeUserOwner, @@ -238,7 +238,7 @@ func (suite *EvaluationReportSuite) TestFetchEvaluationReportByID() { // not found error if the ID is wrong suite.Run("fetch should return a not found error if the reportID doesn't exist", func() { fetcher := NewEvaluationReportFetcher() - officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeQaeCsr}) + officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeQae}) factory.BuildEvaluationReport(suite.DB(), []factory.Customization{ { Model: officeUser, diff --git a/pkg/services/ghc_rate_engine.go b/pkg/services/ghc_rate_engine.go index b018d848d9e..51bd1d29d5e 100644 --- a/pkg/services/ghc_rate_engine.go +++ b/pkg/services/ghc_rate_engine.go @@ -97,7 +97,7 @@ type DomesticDestinationShuttlingPricer interface { // //go:generate mockery --name DomesticCratingPricer type DomesticCratingPricer interface { - Price(appCtx appcontext.AppContext, contractCode string, requestedPickupDate time.Time, billedCubicFeet unit.CubicFeet, servicesScheduleOrigin int) (unit.Cents, PricingDisplayParams, error) + Price(appCtx appcontext.AppContext, contractCode string, requestedPickupDate time.Time, billedCubicFeet unit.CubicFeet, servicesScheduleOrigin int, standaloneCrate bool, standaloneCrateCap unit.Cents) (unit.Cents, PricingDisplayParams, error) ParamsPricer } diff --git a/pkg/services/ghcrateengine/domestic_crating_pricer.go b/pkg/services/ghcrateengine/domestic_crating_pricer.go index 8ef8ebbbe44..a7d18f3ba5e 100644 --- a/pkg/services/ghcrateengine/domestic_crating_pricer.go +++ b/pkg/services/ghcrateengine/domestic_crating_pricer.go @@ -18,8 +18,8 @@ func NewDomesticCratingPricer() services.DomesticCratingPricer { } // Price determines the price for domestic destination first day SIT -func (p domesticCratingPricer) Price(appCtx appcontext.AppContext, contractCode string, referenceDate time.Time, billedCubicFeet unit.CubicFeet, serviceSchedule int) (unit.Cents, services.PricingDisplayParams, error) { - return priceDomesticCrating(appCtx, models.ReServiceCodeDCRT, contractCode, referenceDate, billedCubicFeet, serviceSchedule) +func (p domesticCratingPricer) Price(appCtx appcontext.AppContext, contractCode string, referenceDate time.Time, billedCubicFeet unit.CubicFeet, serviceSchedule int, standaloneCrate bool, standaloneCrateCap unit.Cents) (unit.Cents, services.PricingDisplayParams, error) { + return priceDomesticCrating(appCtx, models.ReServiceCodeDCRT, contractCode, referenceDate, billedCubicFeet, serviceSchedule, standaloneCrate, standaloneCrateCap) } // PriceUsingParams determines the price for domestic destination first day SIT given PaymentServiceItemParams @@ -46,5 +46,16 @@ func (p domesticCratingPricer) PriceUsingParams(appCtx appcontext.AppContext, pa return unit.Cents(0), nil, err } - return p.Price(appCtx, contractCode, referenceDate, cubicFeetBilled, serviceScheduleDestination) + standaloneCrate, err := getParamBool(params, models.ServiceItemParamNameStandaloneCrate) + if err != nil { + return unit.Cents(0), nil, err + } + + standaloneCrateCapParam, err := getParamInt(params, models.ServiceItemParamNameStandaloneCrateCap) + if err != nil { + return unit.Cents(0), nil, err + } + standaloneCrateCap := unit.Cents(float64(standaloneCrateCapParam)) + + return p.Price(appCtx, contractCode, referenceDate, cubicFeetBilled, serviceScheduleDestination, standaloneCrate, standaloneCrateCap) } diff --git a/pkg/services/ghcrateengine/domestic_crating_pricer_test.go b/pkg/services/ghcrateengine/domestic_crating_pricer_test.go index 716969014dc..986e2bac04b 100644 --- a/pkg/services/ghcrateengine/domestic_crating_pricer_test.go +++ b/pkg/services/ghcrateengine/domestic_crating_pricer_test.go @@ -17,6 +17,9 @@ const ( dcrtTestEscalationCompounded = 1.125 dcrtTestBilledCubicFeet = unit.CubicFeet(10) dcrtTestPriceCents = unit.Cents(25880) + dcrtTestStandaloneCrate = false + dcrtTestStandaloneCrateCap = unit.Cents(1000000) + dcrtTestUncappedRequestTotal = unit.Cents(25880) ) var dcrtTestRequestedPickupDate = time.Date(testdatagen.TestYear, time.June, 5, 7, 33, 11, 456, time.UTC) @@ -36,6 +39,7 @@ func (suite *GHCRateEngineServiceSuite) TestDomesticCratingPricer() { {Key: models.ServiceItemParamNameContractYearName, Value: testdatagen.DefaultContractCode}, {Key: models.ServiceItemParamNameEscalationCompounded, Value: FormatEscalation(dcrtTestEscalationCompounded)}, {Key: models.ServiceItemParamNamePriceRateOrFactor, Value: FormatCents(dcrtTestBasePriceCents)}, + {Key: models.ServiceItemParamNameUncappedRequestTotal, Value: FormatCents(dcrtTestUncappedRequestTotal)}, } suite.validatePricerCreatedParams(expectedParams, displayParams) }) @@ -51,7 +55,7 @@ func (suite *GHCRateEngineServiceSuite) TestDomesticCratingPricer() { suite.Run("success without PaymentServiceItemParams", func() { suite.setupDomesticAccessorialPrice(models.ReServiceCodeDCRT, dcrtTestServiceSchedule, dcrtTestBasePriceCents, testdatagen.DefaultContractCode, dcrtTestEscalationCompounded) - priceCents, _, err := pricer.Price(suite.AppContextForTest(), testdatagen.DefaultContractCode, dcrtTestRequestedPickupDate, dcrtTestBilledCubicFeet, dcrtTestServiceSchedule) + priceCents, _, err := pricer.Price(suite.AppContextForTest(), testdatagen.DefaultContractCode, dcrtTestRequestedPickupDate, dcrtTestBilledCubicFeet, dcrtTestServiceSchedule, dcrtTestStandaloneCrate, dcrtTestStandaloneCrateCap) suite.NoError(err) suite.Equal(dcrtTestPriceCents, priceCents) }) @@ -65,14 +69,14 @@ func (suite *GHCRateEngineServiceSuite) TestDomesticCratingPricer() { suite.Run("invalid crating volume", func() { suite.setupDomesticAccessorialPrice(models.ReServiceCodeDCRT, dcrtTestServiceSchedule, dcrtTestBasePriceCents, testdatagen.DefaultContractCode, dcrtTestEscalationCompounded) badVolume := unit.CubicFeet(3.0) - _, _, err := pricer.Price(suite.AppContextForTest(), testdatagen.DefaultContractCode, dcrtTestRequestedPickupDate, badVolume, dcrtTestServiceSchedule) + _, _, err := pricer.Price(suite.AppContextForTest(), testdatagen.DefaultContractCode, dcrtTestRequestedPickupDate, badVolume, dcrtTestServiceSchedule, dcrtTestStandaloneCrate, dcrtTestStandaloneCrateCap) suite.Error(err) suite.Contains(err.Error(), "crate must be billed for a minimum of 4 cubic feet") }) suite.Run("not finding a rate record", func() { suite.setupDomesticAccessorialPrice(models.ReServiceCodeDCRT, dcrtTestServiceSchedule, dcrtTestBasePriceCents, testdatagen.DefaultContractCode, dcrtTestEscalationCompounded) - _, _, err := pricer.Price(suite.AppContextForTest(), "BOGUS", dcrtTestRequestedPickupDate, dcrtTestBilledCubicFeet, dcrtTestServiceSchedule) + _, _, err := pricer.Price(suite.AppContextForTest(), "BOGUS", dcrtTestRequestedPickupDate, dcrtTestBilledCubicFeet, dcrtTestServiceSchedule, dcrtTestStandaloneCrate, dcrtTestStandaloneCrateCap) suite.Error(err) suite.Contains(err.Error(), "could not lookup Domestic Accessorial Area Price") }) @@ -80,7 +84,7 @@ func (suite *GHCRateEngineServiceSuite) TestDomesticCratingPricer() { suite.Run("not finding a contract year record", func() { suite.setupDomesticAccessorialPrice(models.ReServiceCodeDCRT, dcrtTestServiceSchedule, dcrtTestBasePriceCents, testdatagen.DefaultContractCode, dcrtTestEscalationCompounded) twoYearsLaterPickupDate := dcrtTestRequestedPickupDate.AddDate(2, 0, 0) - _, _, err := pricer.Price(suite.AppContextForTest(), testdatagen.DefaultContractCode, twoYearsLaterPickupDate, dcrtTestBilledCubicFeet, dcrtTestServiceSchedule) + _, _, err := pricer.Price(suite.AppContextForTest(), testdatagen.DefaultContractCode, twoYearsLaterPickupDate, dcrtTestBilledCubicFeet, dcrtTestServiceSchedule, dcrtTestStandaloneCrate, dcrtTestStandaloneCrateCap) suite.Error(err) suite.Contains(err.Error(), "could not lookup contract year") }) @@ -111,6 +115,16 @@ func (suite *GHCRateEngineServiceSuite) setupDomesticCratingServiceItem(cubicFee KeyType: models.ServiceItemParamTypeInteger, Value: strconv.Itoa(dcrtTestServiceSchedule), }, + { + Key: models.ServiceItemParamNameStandaloneCrate, + KeyType: models.ServiceItemParamTypeBoolean, + Value: strconv.FormatBool(false), + }, + { + Key: models.ServiceItemParamNameStandaloneCrateCap, + KeyType: models.ServiceItemParamTypeInteger, + Value: strconv.FormatInt(100000, 10), + }, }, nil, nil, ) } diff --git a/pkg/services/ghcrateengine/domestic_uncrating_pricer.go b/pkg/services/ghcrateengine/domestic_uncrating_pricer.go index cedae850b7e..da8f4105670 100644 --- a/pkg/services/ghcrateengine/domestic_uncrating_pricer.go +++ b/pkg/services/ghcrateengine/domestic_uncrating_pricer.go @@ -19,7 +19,7 @@ func NewDomesticUncratingPricer() services.DomesticUncratingPricer { // Price determines the price for domestic destination first day SIT func (p domesticUncratingPricer) Price(appCtx appcontext.AppContext, contractCode string, referenceDate time.Time, billedCubicFeet unit.CubicFeet, serviceSchedule int) (unit.Cents, services.PricingDisplayParams, error) { - return priceDomesticCrating(appCtx, models.ReServiceCodeDUCRT, contractCode, referenceDate, billedCubicFeet, serviceSchedule) + return priceDomesticCrating(appCtx, models.ReServiceCodeDUCRT, contractCode, referenceDate, billedCubicFeet, serviceSchedule, false, 0) } // PriceUsingParams determines the price for domestic destination first day SIT given PaymentServiceItemParams diff --git a/pkg/services/ghcrateengine/domestic_uncrating_pricer_test.go b/pkg/services/ghcrateengine/domestic_uncrating_pricer_test.go index 54bcdc53332..b4f5c5a829e 100644 --- a/pkg/services/ghcrateengine/domestic_uncrating_pricer_test.go +++ b/pkg/services/ghcrateengine/domestic_uncrating_pricer_test.go @@ -18,6 +18,7 @@ const ( ducrtTestEscalationCompounded = 1.125 ducrtTestBilledCubicFeet = 10 ducrtTestPriceCents = unit.Cents(6690) + ducrtTestUncappedRequestTotal = unit.Cents(6690) ) var ducrtTestRequestedPickupDate = time.Date(testdatagen.TestYear, time.June, 5, 7, 33, 11, 456, time.UTC) @@ -37,6 +38,7 @@ func (suite *GHCRateEngineServiceSuite) TestDomesticUncratingPricer() { {Key: models.ServiceItemParamNameContractYearName, Value: testdatagen.DefaultContractCode}, {Key: models.ServiceItemParamNameEscalationCompounded, Value: FormatEscalation(ducrtTestEscalationCompounded)}, {Key: models.ServiceItemParamNamePriceRateOrFactor, Value: FormatCents(ducrtTestBasePriceCents)}, + {Key: models.ServiceItemParamNameUncappedRequestTotal, Value: FormatCents(ducrtTestUncappedRequestTotal)}, } suite.validatePricerCreatedParams(expectedParams, displayParams) }) diff --git a/pkg/services/ghcrateengine/param_convert.go b/pkg/services/ghcrateengine/param_convert.go index f63b6d3e6d8..16ecf8d9fe6 100644 --- a/pkg/services/ghcrateengine/param_convert.go +++ b/pkg/services/ghcrateengine/param_convert.go @@ -93,6 +93,25 @@ func getParamTime(params models.PaymentServiceItemParams, name models.ServiceIte return timeValue, nil } +func getParamBool(params models.PaymentServiceItemParams, name models.ServiceItemParamName) (bool, error) { + paymentServiceItemParam := getPaymentServiceItemParam(params, name) + if paymentServiceItemParam == nil { + return false, fmt.Errorf("could not find param with key %s", name) + } + + paramType := paymentServiceItemParam.ServiceItemParamKey.Type + if paramType != models.ServiceItemParamTypeBoolean { + return false, fmt.Errorf("trying to convert %s to an bool, but param is of type %s", name, paramType) + } + + value, err := strconv.ParseBool(paymentServiceItemParam.Value) + if err != nil { + return false, fmt.Errorf("could not convert value %s to an bool: %w", paymentServiceItemParam.Value, err) + } + + return value, nil +} + func getPaymentServiceItemParam(params models.PaymentServiceItemParams, name models.ServiceItemParamName) *models.PaymentServiceItemParam { for _, param := range params { if param.ServiceItemParamKey.Key == name { diff --git a/pkg/services/ghcrateengine/pricer_helpers.go b/pkg/services/ghcrateengine/pricer_helpers.go index a4efdd4fe99..8dbdf1b2886 100644 --- a/pkg/services/ghcrateengine/pricer_helpers.go +++ b/pkg/services/ghcrateengine/pricer_helpers.go @@ -381,7 +381,7 @@ func priceDomesticShuttling(appCtx appcontext.AppContext, shuttlingCode models.R return totalCost, params, nil } -func priceDomesticCrating(appCtx appcontext.AppContext, code models.ReServiceCode, contractCode string, referenceDate time.Time, billedCubicFeet unit.CubicFeet, serviceSchedule int) (unit.Cents, services.PricingDisplayParams, error) { +func priceDomesticCrating(appCtx appcontext.AppContext, code models.ReServiceCode, contractCode string, referenceDate time.Time, billedCubicFeet unit.CubicFeet, serviceSchedule int, standaloneCrate bool, standaloneCrateCap unit.Cents) (unit.Cents, services.PricingDisplayParams, error) { if code != models.ReServiceCodeDCRT && code != models.ReServiceCodeDUCRT { return 0, nil, fmt.Errorf("unsupported domestic crating code of %s", code) } @@ -416,7 +416,16 @@ func priceDomesticCrating(appCtx appcontext.AppContext, code models.ReServiceCod Key: models.ServiceItemParamNameEscalationCompounded, Value: FormatEscalation(contractYear.EscalationCompounded), }, + { + Key: models.ServiceItemParamNameUncappedRequestTotal, + Value: FormatCents(totalCost), + }, } + + if (standaloneCrate) && (totalCost > standaloneCrateCap) { + totalCost = standaloneCrateCap + } + return totalCost, params, nil } diff --git a/pkg/services/ghcrateengine/pricer_helpers_test.go b/pkg/services/ghcrateengine/pricer_helpers_test.go index fe22303edce..dc0561fa132 100644 --- a/pkg/services/ghcrateengine/pricer_helpers_test.go +++ b/pkg/services/ghcrateengine/pricer_helpers_test.go @@ -599,7 +599,7 @@ func (suite *GHCRateEngineServiceSuite) Test_priceDomesticCrating() { suite.Run("crating golden path", func() { suite.setupDomesticAccessorialPrice(models.ReServiceCodeDCRT, dcrtTestServiceSchedule, dcrtTestBasePriceCents, testdatagen.DefaultContractCode, dcrtTestEscalationCompounded) - priceCents, displayParams, err := priceDomesticCrating(suite.AppContextForTest(), models.ReServiceCodeDCRT, testdatagen.DefaultContractCode, dcrtTestRequestedPickupDate, dcrtTestBilledCubicFeet, dcrtTestServiceSchedule) + priceCents, displayParams, err := priceDomesticCrating(suite.AppContextForTest(), models.ReServiceCodeDCRT, testdatagen.DefaultContractCode, dcrtTestRequestedPickupDate, dcrtTestBilledCubicFeet, dcrtTestServiceSchedule, dcrtTestStandaloneCrate, dcrtTestStandaloneCrateCap) suite.NoError(err) suite.Equal(dcrtTestPriceCents, priceCents) @@ -607,13 +607,14 @@ func (suite *GHCRateEngineServiceSuite) Test_priceDomesticCrating() { {Key: models.ServiceItemParamNameContractYearName, Value: testdatagen.DefaultContractCode}, {Key: models.ServiceItemParamNameEscalationCompounded, Value: FormatEscalation(dcrtTestEscalationCompounded)}, {Key: models.ServiceItemParamNamePriceRateOrFactor, Value: FormatCents(dcrtTestBasePriceCents)}, + {Key: models.ServiceItemParamNameUncappedRequestTotal, Value: FormatCents(dcrtTestUncappedRequestTotal)}, } suite.validatePricerCreatedParams(expectedParams, displayParams) }) suite.Run("crating golden path with truncation", func() { suite.setupDomesticAccessorialPrice(models.ReServiceCodeDCRT, dcrtTestServiceSchedule, dcrtTestBasePriceCents, testdatagen.DefaultContractCode, dcrtTestEscalationCompounded) - priceCents, displayParams, err := priceDomesticCrating(suite.AppContextForTest(), models.ReServiceCodeDCRT, testdatagen.DefaultContractCode, dcrtTestRequestedPickupDate, unit.CubicFeet(8.90625), dcrtTestServiceSchedule) + priceCents, displayParams, err := priceDomesticCrating(suite.AppContextForTest(), models.ReServiceCodeDCRT, testdatagen.DefaultContractCode, dcrtTestRequestedPickupDate, unit.CubicFeet(8.90625), dcrtTestServiceSchedule, dcrtTestStandaloneCrate, dcrtTestStandaloneCrateCap) suite.NoError(err) suite.Equal(unit.Cents(23049), priceCents) @@ -621,13 +622,14 @@ func (suite *GHCRateEngineServiceSuite) Test_priceDomesticCrating() { {Key: models.ServiceItemParamNameContractYearName, Value: testdatagen.DefaultContractCode}, {Key: models.ServiceItemParamNameEscalationCompounded, Value: FormatEscalation(dcrtTestEscalationCompounded)}, {Key: models.ServiceItemParamNamePriceRateOrFactor, Value: FormatCents(dcrtTestBasePriceCents)}, + {Key: models.ServiceItemParamNameUncappedRequestTotal, Value: FormatCents(23049)}, } suite.validatePricerCreatedParams(expectedParams, displayParams) }) suite.Run("invalid service code", func() { suite.setupDomesticAccessorialPrice(models.ReServiceCodeDCRT, dcrtTestServiceSchedule, dcrtTestBasePriceCents, testdatagen.DefaultContractCode, dcrtTestEscalationCompounded) - _, _, err := priceDomesticCrating(suite.AppContextForTest(), models.ReServiceCodeCS, testdatagen.DefaultContractCode, dcrtTestRequestedPickupDate, dcrtTestBilledCubicFeet, dcrtTestServiceSchedule) + _, _, err := priceDomesticCrating(suite.AppContextForTest(), models.ReServiceCodeCS, testdatagen.DefaultContractCode, dcrtTestRequestedPickupDate, dcrtTestBilledCubicFeet, dcrtTestServiceSchedule, dcrtTestStandaloneCrate, dcrtTestStandaloneCrateCap) suite.Error(err) suite.Contains(err.Error(), "unsupported domestic crating code") @@ -637,7 +639,7 @@ func (suite *GHCRateEngineServiceSuite) Test_priceDomesticCrating() { suite.setupDomesticAccessorialPrice(models.ReServiceCodeDCRT, dcrtTestServiceSchedule, dcrtTestBasePriceCents, testdatagen.DefaultContractCode, dcrtTestEscalationCompounded) badSize := unit.CubicFeet(1.0) - _, _, err := priceDomesticCrating(suite.AppContextForTest(), models.ReServiceCodeDCRT, testdatagen.DefaultContractCode, dcrtTestRequestedPickupDate, badSize, dcrtTestServiceSchedule) + _, _, err := priceDomesticCrating(suite.AppContextForTest(), models.ReServiceCodeDCRT, testdatagen.DefaultContractCode, dcrtTestRequestedPickupDate, badSize, dcrtTestServiceSchedule, dcrtTestStandaloneCrate, dcrtTestStandaloneCrateCap) suite.Error(err) suite.Contains(err.Error(), "crate must be billed for a minimum of 4 cubic feet") @@ -646,7 +648,7 @@ func (suite *GHCRateEngineServiceSuite) Test_priceDomesticCrating() { suite.Run("not finding a rate record", func() { suite.setupDomesticAccessorialPrice(models.ReServiceCodeDCRT, dcrtTestServiceSchedule, dcrtTestBasePriceCents, testdatagen.DefaultContractCode, dcrtTestEscalationCompounded) - _, _, err := priceDomesticCrating(suite.AppContextForTest(), models.ReServiceCodeDCRT, "BOGUS", dcrtTestRequestedPickupDate, dcrtTestBilledCubicFeet, dcrtTestServiceSchedule) + _, _, err := priceDomesticCrating(suite.AppContextForTest(), models.ReServiceCodeDCRT, "BOGUS", dcrtTestRequestedPickupDate, dcrtTestBilledCubicFeet, dcrtTestServiceSchedule, dcrtTestStandaloneCrate, dcrtTestStandaloneCrateCap) suite.Error(err) suite.Contains(err.Error(), "could not lookup Domestic Accessorial Area Price") @@ -656,7 +658,7 @@ func (suite *GHCRateEngineServiceSuite) Test_priceDomesticCrating() { suite.setupDomesticAccessorialPrice(models.ReServiceCodeDCRT, dcrtTestServiceSchedule, dcrtTestBasePriceCents, testdatagen.DefaultContractCode, dcrtTestEscalationCompounded) twoYearsLaterPickupDate := dcrtTestRequestedPickupDate.AddDate(2, 0, 0) - _, _, err := priceDomesticCrating(suite.AppContextForTest(), models.ReServiceCodeDCRT, testdatagen.DefaultContractCode, twoYearsLaterPickupDate, dcrtTestBilledCubicFeet, dcrtTestServiceSchedule) + _, _, err := priceDomesticCrating(suite.AppContextForTest(), models.ReServiceCodeDCRT, testdatagen.DefaultContractCode, twoYearsLaterPickupDate, dcrtTestBilledCubicFeet, dcrtTestServiceSchedule, dcrtTestStandaloneCrate, dcrtTestStandaloneCrateCap) suite.Error(err) suite.Contains(err.Error(), "could not lookup contract year") diff --git a/pkg/services/mocks/DomesticCratingPricer.go b/pkg/services/mocks/DomesticCratingPricer.go index b98aa58f430..909b704749c 100644 --- a/pkg/services/mocks/DomesticCratingPricer.go +++ b/pkg/services/mocks/DomesticCratingPricer.go @@ -20,32 +20,32 @@ type DomesticCratingPricer struct { mock.Mock } -// Price provides a mock function with given fields: appCtx, contractCode, requestedPickupDate, billedCubicFeet, servicesScheduleOrigin -func (_m *DomesticCratingPricer) Price(appCtx appcontext.AppContext, contractCode string, requestedPickupDate time.Time, billedCubicFeet unit.CubicFeet, servicesScheduleOrigin int) (unit.Cents, services.PricingDisplayParams, error) { - ret := _m.Called(appCtx, contractCode, requestedPickupDate, billedCubicFeet, servicesScheduleOrigin) +// Price provides a mock function with given fields: appCtx, contractCode, requestedPickupDate, billedCubicFeet, servicesScheduleOrigin, standaloneCrate, standaloneCrateCap +func (_m *DomesticCratingPricer) Price(appCtx appcontext.AppContext, contractCode string, requestedPickupDate time.Time, billedCubicFeet unit.CubicFeet, servicesScheduleOrigin int, standaloneCrate bool, standaloneCrateCap unit.Cents) (unit.Cents, services.PricingDisplayParams, error) { + ret := _m.Called(appCtx, contractCode, requestedPickupDate, billedCubicFeet, servicesScheduleOrigin, standaloneCrate, standaloneCrateCap) var r0 unit.Cents var r1 services.PricingDisplayParams var r2 error - if rf, ok := ret.Get(0).(func(appcontext.AppContext, string, time.Time, unit.CubicFeet, int) (unit.Cents, services.PricingDisplayParams, error)); ok { - return rf(appCtx, contractCode, requestedPickupDate, billedCubicFeet, servicesScheduleOrigin) + if rf, ok := ret.Get(0).(func(appcontext.AppContext, string, time.Time, unit.CubicFeet, int, bool, unit.Cents) (unit.Cents, services.PricingDisplayParams, error)); ok { + return rf(appCtx, contractCode, requestedPickupDate, billedCubicFeet, servicesScheduleOrigin, standaloneCrate, standaloneCrateCap) } - if rf, ok := ret.Get(0).(func(appcontext.AppContext, string, time.Time, unit.CubicFeet, int) unit.Cents); ok { - r0 = rf(appCtx, contractCode, requestedPickupDate, billedCubicFeet, servicesScheduleOrigin) + if rf, ok := ret.Get(0).(func(appcontext.AppContext, string, time.Time, unit.CubicFeet, int, bool, unit.Cents) unit.Cents); ok { + r0 = rf(appCtx, contractCode, requestedPickupDate, billedCubicFeet, servicesScheduleOrigin, standaloneCrate, standaloneCrateCap) } else { r0 = ret.Get(0).(unit.Cents) } - if rf, ok := ret.Get(1).(func(appcontext.AppContext, string, time.Time, unit.CubicFeet, int) services.PricingDisplayParams); ok { - r1 = rf(appCtx, contractCode, requestedPickupDate, billedCubicFeet, servicesScheduleOrigin) + if rf, ok := ret.Get(1).(func(appcontext.AppContext, string, time.Time, unit.CubicFeet, int, bool, unit.Cents) services.PricingDisplayParams); ok { + r1 = rf(appCtx, contractCode, requestedPickupDate, billedCubicFeet, servicesScheduleOrigin, standaloneCrate, standaloneCrateCap) } else { if ret.Get(1) != nil { r1 = ret.Get(1).(services.PricingDisplayParams) } } - if rf, ok := ret.Get(2).(func(appcontext.AppContext, string, time.Time, unit.CubicFeet, int) error); ok { - r2 = rf(appCtx, contractCode, requestedPickupDate, billedCubicFeet, servicesScheduleOrigin) + if rf, ok := ret.Get(2).(func(appcontext.AppContext, string, time.Time, unit.CubicFeet, int, bool, unit.Cents) error); ok { + r2 = rf(appCtx, contractCode, requestedPickupDate, billedCubicFeet, servicesScheduleOrigin, standaloneCrate, standaloneCrateCap) } else { r2 = ret.Error(2) } diff --git a/pkg/services/move/move_searcher_test.go b/pkg/services/move/move_searcher_test.go index 87c81acbcaf..7aa5b384028 100644 --- a/pkg/services/move/move_searcher_test.go +++ b/pkg/services/move/move_searcher_test.go @@ -14,7 +14,7 @@ func (suite *MoveServiceSuite) TestMoveSearch() { searcher := NewMoveSearcher() suite.Run("search with no filters should fail", func() { - qaeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeQaeCsr}) + qaeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeQae}) session := auth.Session{ ApplicationName: auth.OfficeApp, Roles: qaeUser.User.Roles, @@ -43,7 +43,7 @@ func (suite *MoveServiceSuite) TestMoveSearch() { suite.Error(err) }) suite.Run("search with valid locator", func() { - qaeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeQaeCsr}) + qaeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeQae}) session := auth.Session{ ApplicationName: auth.OfficeApp, Roles: qaeUser.User.Roles, @@ -74,7 +74,7 @@ func (suite *MoveServiceSuite) TestMoveSearch() { suite.Equal(firstMove.Locator, moves[0].Locator) }) suite.Run("search with valid DOD ID", func() { - qaeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeQaeCsr}) + qaeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeQae}) session := auth.Session{ ApplicationName: auth.OfficeApp, Roles: qaeUser.User.Roles, @@ -105,7 +105,7 @@ func (suite *MoveServiceSuite) TestMoveSearch() { suite.Equal(secondMove.Locator, moves[0].Locator) }) suite.Run("search with customer name", func() { - qaeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeQaeCsr}) + qaeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeQae}) session := auth.Session{ ApplicationName: auth.OfficeApp, Roles: qaeUser.User.Roles, @@ -142,7 +142,7 @@ func (suite *MoveServiceSuite) TestMoveSearch() { suite.Equal(firstMove.Locator, moves[0].Locator) }) suite.Run("search with both DOD ID and locator filters should fail", func() { - qaeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeQaeCsr}) + qaeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeQae}) session := auth.Session{ ApplicationName: auth.OfficeApp, Roles: qaeUser.User.Roles, @@ -175,7 +175,7 @@ func (suite *MoveServiceSuite) TestMoveSearch() { suite.Error(err) }) suite.Run("search with no results", func() { - qaeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeQaeCsr}) + qaeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeQae}) session := auth.Session{ ApplicationName: auth.OfficeApp, Roles: qaeUser.User.Roles, @@ -190,7 +190,7 @@ func (suite *MoveServiceSuite) TestMoveSearch() { suite.Len(moves, 0) }) suite.Run("test pagination", func() { - qaeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeQaeCsr}) + qaeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeQae}) session := auth.Session{ ApplicationName: auth.OfficeApp, Roles: qaeUser.User.Roles, @@ -366,7 +366,7 @@ func (suite *MoveServiceSuite) TestMoveSearchOrdering() { testMoves := models.Moves{} suite.NoError(suite.DB().EagerPreload("Orders", "Orders.NewDutyLocation", "Orders.NewDutyLocation.Address").All(&testMoves)) - qaeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeQaeCsr}) + qaeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeQae}) session := auth.Session{ ApplicationName: auth.OfficeApp, Roles: qaeUser.User.Roles, @@ -404,7 +404,7 @@ func (suite *MoveServiceSuite) TestMoveSearchOrdering() { nameToSearch := "maria johnson" searcher := NewMoveSearcher() - qaeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeQaeCsr}) + qaeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeQae}) session := auth.Session{ ApplicationName: auth.OfficeApp, Roles: qaeUser.User.Roles, diff --git a/pkg/services/move_history/move_history_fetcher_test.go b/pkg/services/move_history/move_history_fetcher_test.go index 6b7f6101b96..13b85471c12 100644 --- a/pkg/services/move_history/move_history_fetcher_test.go +++ b/pkg/services/move_history/move_history_fetcher_test.go @@ -18,6 +18,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/ghcrateengine" moverouter "github.com/transcom/mymove/pkg/services/move" mtoserviceitem "github.com/transcom/mymove/pkg/services/mto_service_item" mtoshipment "github.com/transcom/mymove/pkg/services/mto_shipment" @@ -548,7 +549,7 @@ func (suite *MoveHistoryServiceSuite) TestMoveHistoryFetcherScenarios() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) dimension := models.MTOServiceItemDimension{ Type: models.DimensionTypeItem, @@ -621,7 +622,7 @@ func (suite *MoveHistoryServiceSuite) TestMoveHistoryFetcherScenarios() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) reService := factory.BuildReServiceByCode(suite.DB(), models.ReServiceCodeMS) diff --git a/pkg/services/move_task_order/move_task_order_updater_test.go b/pkg/services/move_task_order/move_task_order_updater_test.go index e69b5330f0d..e28f98a1f05 100644 --- a/pkg/services/move_task_order/move_task_order_updater_test.go +++ b/pkg/services/move_task_order/move_task_order_updater_test.go @@ -12,6 +12,7 @@ import ( "github.com/transcom/mymove/pkg/factory" "github.com/transcom/mymove/pkg/models" routemocks "github.com/transcom/mymove/pkg/route/mocks" + "github.com/transcom/mymove/pkg/services/ghcrateengine" "github.com/transcom/mymove/pkg/services/mocks" moverouter "github.com/transcom/mymove/pkg/services/move" mt "github.com/transcom/mymove/pkg/services/move_task_order" @@ -31,7 +32,7 @@ func (suite *MoveTaskOrderServiceSuite) TestMoveTaskOrderUpdater_UpdateStatusSer ).Return(400, nil) mtoUpdater := mt.NewMoveTaskOrderUpdater( queryBuilder, - mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter), + mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), moveRouter, ) @@ -230,7 +231,7 @@ func (suite *MoveTaskOrderServiceSuite) TestMoveTaskOrderUpdater_UpdatePostCouns ).Return(400, nil) mtoUpdater := mt.NewMoveTaskOrderUpdater( queryBuilder, - mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter), + mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), moveRouter, ) @@ -369,7 +370,7 @@ func (suite *MoveTaskOrderServiceSuite) TestMoveTaskOrderUpdater_ShowHide() { ).Return(400, nil) updater := mt.NewMoveTaskOrderUpdater( queryBuilder, - mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter), + mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), moveRouter, ) @@ -521,7 +522,7 @@ func (suite *MoveTaskOrderServiceSuite) TestMoveTaskOrderUpdater_MakeAvailableTo mock.Anything, mock.Anything, ).Return(400, nil) - serviceItemCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter) + serviceItemCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) mtoUpdater := mt.NewMoveTaskOrderUpdater(queryBuilder, serviceItemCreator, moveRouter) move := factory.BuildMoveWithShipment(suite.DB(), nil, nil) @@ -558,7 +559,7 @@ func (suite *MoveTaskOrderServiceSuite) TestMoveTaskOrderUpdater_MakeAvailableTo mock.Anything, mock.Anything, ).Return(400, nil) - serviceItemCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter) + serviceItemCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) mtoUpdater := mt.NewMoveTaskOrderUpdater(queryBuilder, serviceItemCreator, moveRouter) move := factory.BuildMoveWithShipment(suite.DB(), nil, nil) @@ -587,7 +588,7 @@ func (suite *MoveTaskOrderServiceSuite) TestMoveTaskOrderUpdater_MakeAvailableTo queryBuilder := query.NewQueryBuilder() moveRouter := moverouter.NewMoveRouter() planner := &routemocks.Planner{} - serviceItemCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter) + serviceItemCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) mtoUpdater := mt.NewMoveTaskOrderUpdater(queryBuilder, serviceItemCreator, moveRouter) move := factory.BuildMoveWithShipment(suite.DB(), nil, nil) @@ -755,7 +756,7 @@ func (suite *MoveTaskOrderServiceSuite) TestMoveTaskOrderUpdater_UpdatePPMType() ).Return(400, nil) updater := mt.NewMoveTaskOrderUpdater( queryBuilder, - mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter), + mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), moveRouter, ) diff --git a/pkg/services/moving_expense/moving_expense_updater.go b/pkg/services/moving_expense/moving_expense_updater.go index 920fb4909e0..4061049eee4 100644 --- a/pkg/services/moving_expense/moving_expense_updater.go +++ b/pkg/services/moving_expense/moving_expense_updater.go @@ -48,6 +48,24 @@ func (f *movingExpenseUpdater) UpdateMovingExpense(appCtx appcontext.AppContext, return nil, err } + if appCtx.Session().IsMilApp() { + if mergedMovingExpense.Amount != nil { + mergedMovingExpense.SubmittedAmount = mergedMovingExpense.Amount + } + if mergedMovingExpense.MovingExpenseType != nil { + mergedMovingExpense.SubmittedMovingExpenseType = mergedMovingExpense.MovingExpenseType + } + if mergedMovingExpense.Description != nil { + mergedMovingExpense.SubmittedDescription = mergedMovingExpense.Description + } + if mergedMovingExpense.SITStartDate != nil { + mergedMovingExpense.SubmittedSITStartDate = mergedMovingExpense.SITStartDate + } + if mergedMovingExpense.SITEndDate != nil { + mergedMovingExpense.SubmittedSITEndDate = mergedMovingExpense.SITEndDate + } + } + txnErr := appCtx.NewTransaction(func(txnCtx appcontext.AppContext) error { verrs, err := txnCtx.DB().Eager().ValidateAndUpdate(&mergedMovingExpense) @@ -114,13 +132,23 @@ func mergeMovingExpense(updatedMovingExpense models.MovingExpense, originalMovin if movingExpenseReceiptType == models.MovingExpenseReceiptTypeStorage { mergedMovingExpense.SITStartDate = services.SetOptionalDateTimeField(updatedMovingExpense.SITStartDate, mergedMovingExpense.SITStartDate) mergedMovingExpense.SITEndDate = services.SetOptionalDateTimeField(updatedMovingExpense.SITEndDate, mergedMovingExpense.SITEndDate) - mergedMovingExpense.WeightStored = services.SetOptionalPoundField(updatedMovingExpense.WeightStored, mergedMovingExpense.WeightStored) + + // if weightStored was omitted we check for the zero value that is passed in and don't update it since we don't want to null out + // a previous value + if *updatedMovingExpense.WeightStored != 0 { + mergedMovingExpense.WeightStored = services.SetOptionalPoundField(updatedMovingExpense.WeightStored, mergedMovingExpense.WeightStored) + } + + if updatedMovingExpense.SITLocation != nil { + mergedMovingExpense.SITLocation = updatedMovingExpense.SITLocation + } } else if originalMovingExpense.MovingExpenseType != nil && *originalMovingExpense.MovingExpenseType == models.MovingExpenseReceiptTypeStorage { // The receipt type has been changed from storage to something else so we should clear // the start and end values mergedMovingExpense.SITStartDate = nil mergedMovingExpense.SITEndDate = nil mergedMovingExpense.WeightStored = nil + mergedMovingExpense.SITLocation = nil } } else { diff --git a/pkg/services/moving_expense/moving_expense_updater_test.go b/pkg/services/moving_expense/moving_expense_updater_test.go index 02a367d381c..d7619bf28f2 100644 --- a/pkg/services/moving_expense/moving_expense_updater_test.go +++ b/pkg/services/moving_expense/moving_expense_updater_test.go @@ -209,6 +209,9 @@ func (suite *MovingExpenseSuite) TestUpdateMovingExpense() { suite.Equal(*expectedMovingExpense.PaidWithGTCC, *updatedMovingExpense.PaidWithGTCC) suite.Equal(*expectedMovingExpense.Amount, *updatedMovingExpense.Amount) suite.Equal(*expectedMovingExpense.MissingReceipt, *updatedMovingExpense.MissingReceipt) + suite.Equal(*expectedMovingExpense.Amount, *updatedMovingExpense.SubmittedAmount) + suite.Equal(*expectedMovingExpense.MovingExpenseType, *updatedMovingExpense.SubmittedMovingExpenseType) + suite.Equal(*expectedMovingExpense.Description, *updatedMovingExpense.SubmittedDescription) // Only the storage type receipt should be able to set these fields, would we rather reject // the update outright than fail silently? suite.Nil(updatedMovingExpense.SITStartDate) @@ -254,6 +257,8 @@ func (suite *MovingExpenseSuite) TestUpdateMovingExpense() { // Only the storage type receipt should be able to set these fields suite.Nil(updatedMovingExpense.SITStartDate) suite.Nil(updatedMovingExpense.SITEndDate) + // Office user updates should not update SubmittedAmount + suite.Nil(updatedMovingExpense.SubmittedAmount) }) suite.Run("Successfully updates storage receipt type", func() { @@ -266,6 +271,7 @@ func (suite *MovingExpenseSuite) TestUpdateMovingExpense() { storageStart := time.Now() storageEnd := storageStart.Add(7 * time.Hour * 24) weightStored := 2000 + sitLocation := "ORIGIN" expectedMovingExpense := &models.MovingExpense{ ID: originalMovingExpense.ID, @@ -277,6 +283,7 @@ func (suite *MovingExpenseSuite) TestUpdateMovingExpense() { SITStartDate: &storageStart, SITEndDate: &storageEnd, WeightStored: (*unit.Pound)(&weightStored), + SITLocation: (*models.SITLocationType)(&sitLocation), } updatedMovingExpense, updateErr := updater.UpdateMovingExpense(appCtx, *expectedMovingExpense, etag.GenerateEtag(originalMovingExpense.UpdatedAt)) @@ -292,6 +299,7 @@ func (suite *MovingExpenseSuite) TestUpdateMovingExpense() { suite.Equal(*expectedMovingExpense.SITStartDate, *updatedMovingExpense.SITStartDate) suite.Equal(*expectedMovingExpense.SITEndDate, *updatedMovingExpense.SITEndDate) suite.Equal(*expectedMovingExpense.WeightStored, *updatedMovingExpense.WeightStored) + suite.Equal(*expectedMovingExpense.SITLocation, *updatedMovingExpense.SITLocation) suite.Nil(updatedMovingExpense.Status) suite.Nil(updatedMovingExpense.Reason) }) @@ -301,11 +309,13 @@ func (suite *MovingExpenseSuite) TestUpdateMovingExpense() { storageReceiptType := models.MovingExpenseReceiptTypeStorage weightStored := 2000 + sitLocation := "ORIGIN" originalMovingExpense := setupForTest(appCtx, &models.MovingExpense{ MovingExpenseType: &storageReceiptType, SITStartDate: models.TimePointer(time.Now()), SITEndDate: models.TimePointer(time.Now()), WeightStored: (*unit.Pound)(&weightStored), + SITLocation: (*models.SITLocationType)(&sitLocation), }, true) updater := NewCustomerMovingExpenseUpdater() @@ -333,6 +343,7 @@ func (suite *MovingExpenseSuite) TestUpdateMovingExpense() { suite.Nil(updatedMovingExpense.SITStartDate) suite.Nil(updatedMovingExpense.SITEndDate) suite.Nil(updatedMovingExpense.WeightStored) + suite.Nil(updatedMovingExpense.SITLocation) suite.Nil(updatedMovingExpense.Status) suite.Nil(updatedMovingExpense.Reason) }) diff --git a/pkg/services/mto_service_item/mto_service_item_creator.go b/pkg/services/mto_service_item/mto_service_item_creator.go index 00d3ca40c2d..adb25b669e5 100644 --- a/pkg/services/mto_service_item/mto_service_item_creator.go +++ b/pkg/services/mto_service_item/mto_service_item_creator.go @@ -5,6 +5,7 @@ import ( "fmt" "strconv" "strings" + "time" "github.com/gobuffalo/validate/v3" "github.com/gofrs/uuid" @@ -15,6 +16,7 @@ import ( "github.com/transcom/mymove/pkg/route" "github.com/transcom/mymove/pkg/services" "github.com/transcom/mymove/pkg/services/query" + "github.com/transcom/mymove/pkg/unit" ) type createMTOServiceItemQueryBuilder interface { @@ -24,10 +26,247 @@ type createMTOServiceItemQueryBuilder interface { } type mtoServiceItemCreator struct { - planner route.Planner - builder createMTOServiceItemQueryBuilder - createNewBuilder func() createMTOServiceItemQueryBuilder - moveRouter services.MoveRouter + planner route.Planner + builder createMTOServiceItemQueryBuilder + createNewBuilder func() createMTOServiceItemQueryBuilder + moveRouter services.MoveRouter + unpackPricer services.DomesticUnpackPricer + packPricer services.DomesticPackPricer + linehaulPricer services.DomesticLinehaulPricer + shorthaulPricer services.DomesticShorthaulPricer + originPricer services.DomesticOriginPricer + destinationPricer services.DomesticDestinationPricer + fuelSurchargePricer services.FuelSurchargePricer +} + +func (o *mtoServiceItemCreator) findEstimatedPrice(appCtx appcontext.AppContext, serviceItem *models.MTOServiceItem, mtoShipment models.MTOShipment) (unit.Cents, error) { + if serviceItem.ReService.Code == models.ReServiceCodeDOP || + serviceItem.ReService.Code == models.ReServiceCodeDPK || + serviceItem.ReService.Code == models.ReServiceCodeDDP || + serviceItem.ReService.Code == models.ReServiceCodeDUPK || + serviceItem.ReService.Code == models.ReServiceCodeDLH || + serviceItem.ReService.Code == models.ReServiceCodeDSH || + serviceItem.ReService.Code == models.ReServiceCodeFSC { + + isPPM := false + if mtoShipment.ShipmentType == models.MTOShipmentTypePPM { + isPPM = true + } + requestedPickupDate := *mtoShipment.RequestedPickupDate + currTime := time.Now() + var distance int + primeEstimatedWeight := *mtoShipment.PrimeEstimatedWeight + + contractCode, err := FetchContractCode(appCtx, currTime) + if err != nil { + contractCode, err = FetchContractCode(appCtx, requestedPickupDate) + if err != nil { + return 0, err + } + } + + var price unit.Cents + + // origin + if serviceItem.ReService.Code == models.ReServiceCodeDOP { + domesticServiceArea, err := fetchDomesticServiceArea(appCtx, contractCode, mtoShipment.PickupAddress.PostalCode) + if err != nil { + return 0, err + } + + price, _, err = o.originPricer.Price(appCtx, contractCode, requestedPickupDate, *mtoShipment.PrimeEstimatedWeight, domesticServiceArea.ServiceArea, isPPM) + if err != nil { + return 0, err + } + } + if serviceItem.ReService.Code == models.ReServiceCodeDPK { + domesticServiceArea, err := fetchDomesticServiceArea(appCtx, contractCode, mtoShipment.PickupAddress.PostalCode) + if err != nil { + return 0, err + } + + servicesScheduleOrigin := domesticServiceArea.ServicesSchedule + + price, _, err = o.packPricer.Price(appCtx, contractCode, requestedPickupDate, *mtoShipment.PrimeEstimatedWeight, servicesScheduleOrigin, isPPM) + if err != nil { + return 0, err + } + } + // destination + if serviceItem.ReService.Code == models.ReServiceCodeDDP { + var domesticServiceArea models.ReDomesticServiceArea + if mtoShipment.DestinationAddress != nil { + domesticServiceArea, err = fetchDomesticServiceArea(appCtx, contractCode, mtoShipment.DestinationAddress.PostalCode) + if err != nil { + return 0, err + } + } + + price, _, err = o.destinationPricer.Price(appCtx, contractCode, requestedPickupDate, *mtoShipment.PrimeEstimatedWeight, domesticServiceArea.ServiceArea, isPPM) + if err != nil { + return 0, err + } + } + if serviceItem.ReService.Code == models.ReServiceCodeDUPK { + domesticServiceArea, err := fetchDomesticServiceArea(appCtx, contractCode, mtoShipment.DestinationAddress.PostalCode) + if err != nil { + return 0, err + } + + serviceScheduleDestination := domesticServiceArea.ServicesSchedule + + price, _, err = o.unpackPricer.Price(appCtx, contractCode, requestedPickupDate, *mtoShipment.PrimeEstimatedWeight, serviceScheduleDestination, isPPM) + if err != nil { + return 0, err + } + } + + // linehaul/shorthaul + if serviceItem.ReService.Code == models.ReServiceCodeDLH { + domesticServiceArea, err := fetchDomesticServiceArea(appCtx, contractCode, mtoShipment.PickupAddress.PostalCode) + if err != nil { + return 0, err + } + if mtoShipment.PickupAddress != nil && mtoShipment.DestinationAddress != nil { + distance, err = o.planner.ZipTransitDistance(appCtx, mtoShipment.PickupAddress.PostalCode, mtoShipment.DestinationAddress.PostalCode) + if err != nil { + return 0, err + } + } + price, _, err = o.linehaulPricer.Price(appCtx, contractCode, requestedPickupDate, unit.Miles(distance), *mtoShipment.PrimeEstimatedWeight, domesticServiceArea.ServiceArea, isPPM) + if err != nil { + return 0, err + } + } + if serviceItem.ReService.Code == models.ReServiceCodeDSH { + domesticServiceArea, err := fetchDomesticServiceArea(appCtx, contractCode, mtoShipment.PickupAddress.PostalCode) + if err != nil { + return 0, err + } + if mtoShipment.PickupAddress != nil && mtoShipment.DestinationAddress != nil { + distance, err = o.planner.ZipTransitDistance(appCtx, mtoShipment.PickupAddress.PostalCode, mtoShipment.DestinationAddress.PostalCode) + if err != nil { + return 0, err + } + } + price, _, err = o.shorthaulPricer.Price(appCtx, contractCode, requestedPickupDate, unit.Miles(distance), *mtoShipment.PrimeEstimatedWeight, domesticServiceArea.ServiceArea) + if err != nil { + return 0, err + } + } + // fuel surcharge + if serviceItem.ReService.Code == models.ReServiceCodeFSC { + var pickupDateForFSC time.Time + + // actual pickup date likely won't exist at the time of service item creation, but it could + // use requested pickup date if no actual date exists + if mtoShipment.ActualPickupDate != nil { + pickupDateForFSC = *mtoShipment.ActualPickupDate + } else { + pickupDateForFSC = requestedPickupDate + } + + if mtoShipment.PickupAddress != nil && mtoShipment.DestinationAddress != nil { + distance, err = o.planner.ZipTransitDistance(appCtx, mtoShipment.PickupAddress.PostalCode, mtoShipment.DestinationAddress.PostalCode) + if err != nil { + return 0, err + } + } + + fscWeightBasedDistanceMultiplier, err := LookupFSCWeightBasedDistanceMultiplier(appCtx, primeEstimatedWeight) + if err != nil { + return 0, err + } + fscWeightBasedDistanceMultiplierFloat, err := strconv.ParseFloat(fscWeightBasedDistanceMultiplier, 64) + if err != nil { + return 0, err + } + eiaFuelPrice, err := LookupEIAFuelPrice(appCtx, pickupDateForFSC) + if err != nil { + return 0, err + } + price, _, err = o.fuelSurchargePricer.Price(appCtx, pickupDateForFSC, unit.Miles(distance), primeEstimatedWeight, fscWeightBasedDistanceMultiplierFloat, eiaFuelPrice, isPPM) + if err != nil { + return 0, err + } + + } + return price, nil + } + return 0, nil +} + +func FetchContractCode(appCtx appcontext.AppContext, date time.Time) (string, error) { + var contractYear models.ReContractYear + err := appCtx.DB().EagerPreload("Contract").Where("? between start_date and end_date", date). + First(&contractYear) + if err != nil { + if err == sql.ErrNoRows { + return "", apperror.NewNotFoundError(uuid.Nil, fmt.Sprintf("no contract year found for %s", date.String())) + } + return "", err + } + + contract := contractYear.Contract + + contractCode := contract.Code + return contractCode, nil +} + +func fetchDomesticServiceArea(appCtx appcontext.AppContext, contractCode string, shipmentPostalCode string) (models.ReDomesticServiceArea, error) { + // find the service area by querying for the service area associated with the zip3 + zip := shipmentPostalCode + zip3 := zip[0:3] + var domesticServiceArea models.ReDomesticServiceArea + err := appCtx.DB().Q(). + Join("re_zip3s", "re_zip3s.domestic_service_area_id = re_domestic_service_areas.id"). + Join("re_contracts", "re_contracts.id = re_domestic_service_areas.contract_id"). + Where("re_zip3s.zip3 = ?", zip3). + Where("re_contracts.code = ?", contractCode). + First(&domesticServiceArea) + if err != nil { + return domesticServiceArea, fmt.Errorf("unable to find domestic service area for %s under contract code %s", zip3, contractCode) + } + + return domesticServiceArea, nil +} + +const weightBasedDistanceMultiplierLevelOne = "0.000417" +const weightBasedDistanceMultiplierLevelTwo = "0.0006255" +const weightBasedDistanceMultiplierLevelThree = "0.000834" +const weightBasedDistanceMultiplierLevelFour = "0.00139" + +func LookupFSCWeightBasedDistanceMultiplier(appCtx appcontext.AppContext, primeEstimatedWeight unit.Pound) (string, error) { + weight := primeEstimatedWeight.Int() + + if weight <= 5000 { + return weightBasedDistanceMultiplierLevelOne, nil + } else if weight <= 10000 { + return weightBasedDistanceMultiplierLevelTwo, nil + } else if weight <= 24000 { + return weightBasedDistanceMultiplierLevelThree, nil + //nolint:revive + } else { + return weightBasedDistanceMultiplierLevelFour, nil + } +} + +func LookupEIAFuelPrice(appCtx appcontext.AppContext, pickupDate time.Time) (unit.Millicents, error) { + db := appCtx.DB() + + // Find the GHCDieselFuelPrice object with the closest prior PublicationDate to the ActualPickupDate of the MTOShipment in question + var ghcDieselFuelPrice models.GHCDieselFuelPrice + err := db.Where("publication_date <= ?", pickupDate).Order("publication_date DESC").Last(&ghcDieselFuelPrice) + if err != nil { + switch err { + case sql.ErrNoRows: + return 0, apperror.NewNotFoundError(uuid.Nil, "Looking for GHCDieselFuelPrice") + default: + return 0, apperror.NewQueryError("GHCDieselFuelPrice", err, "") + } + } + + return ghcDieselFuelPrice.FuelPriceInMillicents, nil } func (o *mtoServiceItemCreator) calculateSITDeliveryMiles(appCtx appcontext.AppContext, serviceItem *models.MTOServiceItem, mtoShipment models.MTOShipment) (int, error) { @@ -288,6 +527,17 @@ func (o *mtoServiceItemCreator) CreateMTOServiceItem(appCtx appcontext.AppContex requestedServiceItems = append(requestedServiceItems, *extraServiceItems...) } + + // if estimated weight for shipment provided by the prime, calculate the estimated prices for + // DLH, DPK, DOP, DDP, DUPK + + if mtoShipment.PrimeEstimatedWeight != nil && mtoShipment.RequestedPickupDate != nil { + serviceItemEstimatedPrice, err := o.findEstimatedPrice(appCtx, serviceItem, mtoShipment) + if serviceItemEstimatedPrice != 0 && err == nil { + serviceItem.PricingEstimate = &serviceItemEstimatedPrice + } + } + requestedServiceItems = append(requestedServiceItems, *serviceItem) // create new items in a transaction in case of failure @@ -461,13 +711,13 @@ func (o *mtoServiceItemCreator) makeExtraSITServiceItem(appCtx appcontext.AppCon } // NewMTOServiceItemCreator returns a new MTO service item creator -func NewMTOServiceItemCreator(planner route.Planner, builder createMTOServiceItemQueryBuilder, moveRouter services.MoveRouter) services.MTOServiceItemCreator { +func NewMTOServiceItemCreator(planner route.Planner, builder createMTOServiceItemQueryBuilder, moveRouter services.MoveRouter, unpackPricer services.DomesticUnpackPricer, packPricer services.DomesticPackPricer, linehaulPricer services.DomesticLinehaulPricer, shorthaulPricer services.DomesticShorthaulPricer, originPricer services.DomesticOriginPricer, destinationPricer services.DomesticDestinationPricer, fuelSurchargePricer services.FuelSurchargePricer) services.MTOServiceItemCreator { // used inside a transaction and mocking createNewBuilder := func() createMTOServiceItemQueryBuilder { return query.NewQueryBuilder() } - return &mtoServiceItemCreator{planner: planner, builder: builder, createNewBuilder: createNewBuilder, moveRouter: moveRouter} + return &mtoServiceItemCreator{planner: planner, builder: builder, createNewBuilder: createNewBuilder, moveRouter: moveRouter, unpackPricer: unpackPricer, packPricer: packPricer, linehaulPricer: linehaulPricer, shorthaulPricer: shorthaulPricer, originPricer: originPricer, destinationPricer: destinationPricer, fuelSurchargePricer: fuelSurchargePricer} } func validateTimeMilitaryField(_ appcontext.AppContext, timeMilitary string) error { diff --git a/pkg/services/mto_service_item/mto_service_item_creator_test.go b/pkg/services/mto_service_item/mto_service_item_creator_test.go index 8c14abdd88a..ce882bc9d92 100644 --- a/pkg/services/mto_service_item/mto_service_item_creator_test.go +++ b/pkg/services/mto_service_item/mto_service_item_creator_test.go @@ -24,6 +24,7 @@ import ( "github.com/transcom/mymove/pkg/models" "github.com/transcom/mymove/pkg/route/mocks" "github.com/transcom/mymove/pkg/services" + "github.com/transcom/mymove/pkg/services/ghcrateengine" moverouter "github.com/transcom/mymove/pkg/services/move" "github.com/transcom/mymove/pkg/services/query" "github.com/transcom/mymove/pkg/unit" @@ -192,7 +193,7 @@ func (suite *MTOServiceItemServiceSuite) TestCreateMTOServiceItemWithInvalidMove mock.Anything, mock.Anything, ).Return(400, nil) - creator := NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) serviceItemForUnapprovedMove := suite.buildValidServiceItemWithInvalidMove() createdServiceItems, _, err := creator.CreateMTOServiceItem(suite.AppContextForTest(), &serviceItemForUnapprovedMove) @@ -220,7 +221,7 @@ func (suite *MTOServiceItemServiceSuite) TestCreateMTOServiceItem() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) // Happy path: If the service item is created successfully it should be returned suite.Run("200 Success - Destination SIT Service Item Creation", func() { @@ -694,7 +695,7 @@ func (suite *MTOServiceItemServiceSuite) TestCreateOriginSITServiceItem() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) createdServiceItems, verr, err := creator.CreateMTOServiceItem(suite.AppContextForTest(), &serviceItemDOFSIT) suite.Nil(createdServiceItems) @@ -740,7 +741,7 @@ func (suite *MTOServiceItemServiceSuite) TestCreateOriginSITServiceItem() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) createdServiceItems, _, err := creator.CreateMTOServiceItem(suite.AppContextForTest(), &serviceItemDOFSIT) suite.NotNil(createdServiceItems) @@ -811,7 +812,7 @@ func (suite *MTOServiceItemServiceSuite) TestCreateOriginSITServiceItem() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) // Successful creation of DOFSIT createdServiceItems, _, err := creator.CreateMTOServiceItem(suite.AppContextForTest(), &serviceItemDOFSIT) @@ -937,7 +938,7 @@ func (suite *MTOServiceItemServiceSuite) TestCreateOriginSITServiceItem() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) createdServiceItems, _, err := creator.CreateMTOServiceItem(suite.AppContextForTest(), &serviceItemDOPSIT) @@ -971,7 +972,7 @@ func (suite *MTOServiceItemServiceSuite) TestCreateOriginSITServiceItem() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) createdServiceItems, _, err := creator.CreateMTOServiceItem(suite.AppContextForTest(), &serviceItemDOPSIT) @@ -1004,7 +1005,7 @@ func (suite *MTOServiceItemServiceSuite) TestCreateOriginSITServiceItem() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) createdServiceItems, _, err := creator.CreateMTOServiceItem(suite.AppContextForTest(), &serviceItemDOASIT) @@ -1079,7 +1080,7 @@ func (suite *MTOServiceItemServiceSuite) TestCreateOriginSITServiceItemFailToCre mock.Anything, mock.Anything, ).Return(400, nil) - creator := NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) createdServiceItems, _, err := creator.CreateMTOServiceItem(suite.AppContextForTest(), &serviceItemDOFSIT) suite.Nil(createdServiceItems) @@ -1113,7 +1114,7 @@ func (suite *MTOServiceItemServiceSuite) TestCreateDestSITServiceItem() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) reServiceDDFSIT := factory.BuildReServiceByCode(suite.DB(), models.ReServiceCodeDDFSIT) return shipment, creator, reServiceDDFSIT @@ -1384,7 +1385,7 @@ func (suite *MTOServiceItemServiceSuite) TestCreateDestSITServiceItem() { mock.Anything, mock.Anything, ).Return(400, nil) - creator := NewMTOServiceItemCreator(planner, builder, moveRouter) + creator := NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) createdServiceItems, _, err := creator.CreateMTOServiceItem(suite.AppContextForTest(), &serviceItemDDASIT) suite.Nil(createdServiceItems) diff --git a/pkg/services/mto_shipment/mto_shipment_updater.go b/pkg/services/mto_shipment/mto_shipment_updater.go index f950346ce7a..b98d91d5e67 100644 --- a/pkg/services/mto_shipment/mto_shipment_updater.go +++ b/pkg/services/mto_shipment/mto_shipment_updater.go @@ -3,6 +3,7 @@ package mtoshipment import ( "database/sql" "fmt" + "math" "time" "github.com/gobuffalo/validate/v3" @@ -708,16 +709,27 @@ func (f *mtoShipmentUpdater) updateShipmentRecord(appCtx appcontext.AppContext, // If the estimated weight was updated on an approved shipment then it would mean the move could qualify for // excess weight risk depending on the weight allowance and other shipment estimated weights if newShipment.PrimeEstimatedWeight != nil { - if dbShipment.PrimeEstimatedWeight == nil || *newShipment.PrimeEstimatedWeight != *dbShipment.PrimeEstimatedWeight { - // checking if the total of shipment weight & new prime estimated weight is 90% or more of allowed weight - move, verrs, err := f.moveWeights.CheckExcessWeight(txnAppCtx, dbShipment.MoveTaskOrderID, *newShipment) - if verrs != nil && verrs.HasAny() { - return errors.New(verrs.Error()) - } + // checking if the total of shipment weight & new prime estimated weight is 90% or more of allowed weight + move, verrs, err := f.moveWeights.CheckExcessWeight(txnAppCtx, dbShipment.MoveTaskOrderID, *newShipment) + if verrs != nil && verrs.HasAny() { + return errors.New(verrs.Error()) + } + if err != nil { + return err + } + + // we only want to update the authorized weight if the shipment is approved and the previous weight is nil + // otherwise, shipment_updater will handle updating authorized weight when a shipment is approved + if dbShipment.PrimeEstimatedWeight == nil && newShipment.Status == models.MTOShipmentStatusApproved { + // updates to prime estimated weight should change the authorized weight of the entitlement + // which can be manually adjusted by an office user if needed + err = updateAuthorizedWeight(appCtx, newShipment, move) if err != nil { return err } + } + if dbShipment.PrimeEstimatedWeight == nil || *newShipment.PrimeEstimatedWeight != *dbShipment.PrimeEstimatedWeight { existingMoveStatus := move.Status // if the move is in excess weight risk and the TOO has not acknowledge that, need to change move status to "Approvals Requested" // this will trigger the TOO to acknowledged the excess right, which populates ExcessWeightAcknowledgedAt @@ -1304,3 +1316,28 @@ func UpdateDestinationSITServiceItemsSITDeliveryMiles(planner route.Planner, app return nil } + +func updateAuthorizedWeight(appCtx appcontext.AppContext, shipment *models.MTOShipment, move *models.Move) error { + dBAuthorizedWeight := int(*shipment.PrimeEstimatedWeight) + if len(move.MTOShipments) != 0 { + for _, mtoShipment := range move.MTOShipments { + if mtoShipment.PrimeEstimatedWeight != nil && mtoShipment.Status == models.MTOShipmentStatusApproved && mtoShipment.ID != shipment.ID { + dBAuthorizedWeight += int(*mtoShipment.PrimeEstimatedWeight) + } + } + } + dBAuthorizedWeight = int(math.Round(float64(dBAuthorizedWeight) * 1.10)) + entitlement := move.Orders.Entitlement + entitlement.DBAuthorizedWeight = &dBAuthorizedWeight + verrs, err := appCtx.DB().ValidateAndUpdate(entitlement) + + if verrs != nil && verrs.HasAny() { + invalidInputError := apperror.NewInvalidInputError(shipment.ID, nil, verrs, "There was an issue with validating the updates") + return invalidInputError + } + if err != nil { + return err + } + + return nil +} diff --git a/pkg/services/mto_shipment/mto_shipment_updater_test.go b/pkg/services/mto_shipment/mto_shipment_updater_test.go index 3f1ad37e99b..b2f94469fe1 100644 --- a/pkg/services/mto_shipment/mto_shipment_updater_test.go +++ b/pkg/services/mto_shipment/mto_shipment_updater_test.go @@ -2,6 +2,7 @@ package mtoshipment import ( "fmt" + "math" "time" "github.com/gofrs/uuid" @@ -19,6 +20,7 @@ import ( "github.com/transcom/mymove/pkg/route/mocks" "github.com/transcom/mymove/pkg/services/address" "github.com/transcom/mymove/pkg/services/fetch" + "github.com/transcom/mymove/pkg/services/ghcrateengine" mockservices "github.com/transcom/mymove/pkg/services/mocks" moveservices "github.com/transcom/mymove/pkg/services/move" mtoserviceitem "github.com/transcom/mymove/pkg/services/mto_service_item" @@ -1634,7 +1636,7 @@ func (suite *MTOShipmentServiceSuite) TestUpdateMTOShipmentStatus() { TransitDistancePickupArg = args.Get(1).(string) TransitDistanceDestinationArg = args.Get(2).(string) }) - siCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + siCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) updater := NewMTOShipmentStatusUpdater(builder, siCreator, planner) @@ -2315,6 +2317,43 @@ func (suite *MTOShipmentServiceSuite) TestUpdateShipmentEstimatedWeightMoveExces addressCreator := address.NewAddressCreator() mtoShipmentUpdaterPrime := NewPrimeMTOShipmentUpdater(builder, fetcher, planner, moveRouter, moveWeights, mockSender, &mockShipmentRecalculator, addressUpdater, addressCreator) + suite.Run("Updates to estimated weight change max billable weight", func() { + now := time.Now() + pickupDate := now.AddDate(0, 0, 10) + + primeShipment := factory.BuildMTOShipmentMinimal(suite.DB(), []factory.Customization{ + { + Model: models.MTOShipment{ + Status: models.MTOShipmentStatusApproved, + ApprovedDate: &now, + ScheduledPickupDate: &pickupDate, + }, + }, + { + Model: models.Move{ + AvailableToPrimeAt: &now, + Status: models.MoveStatusAPPROVED, + }, + }, + }, nil) + + suite.Equal(8000, *primeShipment.MoveTaskOrder.Orders.Entitlement.AuthorizedWeight()) + + estimatedWeight := unit.Pound(1234) + primeShipment.Status = "" + primeShipment.PrimeEstimatedWeight = &estimatedWeight + + session := auth.Session{} + _, err := mtoShipmentUpdaterPrime.UpdateMTOShipment(suite.AppContextWithSessionForTest(&session), &primeShipment, etag.GenerateEtag(primeShipment.UpdatedAt), "test") + suite.NoError(err) + + err = suite.DB().Reload(primeShipment.MoveTaskOrder.Orders.Entitlement) + suite.NoError(err) + + estimatedWeight110 := int(math.Round(float64(*primeShipment.PrimeEstimatedWeight) * 1.10)) + suite.Equal(estimatedWeight110, *primeShipment.MoveTaskOrder.Orders.Entitlement.AuthorizedWeight()) + }) + suite.Run("Updating the shipment estimated weight will flag excess weight on the move and transitions move status", func() { now := time.Now() pickupDate := now.AddDate(0, 0, 10) @@ -2739,7 +2778,7 @@ func (suite *MTOShipmentServiceSuite) TestUpdateStatusServiceItems() { mock.Anything, mock.Anything, ).Return(400, nil) - siCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + siCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) updater := NewMTOShipmentStatusUpdater(builder, siCreator, planner) suite.Run("Shipments with different origin/destination ZIP3 have longhaul service item", func() { diff --git a/pkg/services/mto_shipment/rules.go b/pkg/services/mto_shipment/rules.go index 01ecf028f8e..b8c17f16798 100644 --- a/pkg/services/mto_shipment/rules.go +++ b/pkg/services/mto_shipment/rules.go @@ -86,7 +86,7 @@ func checkUpdateAllowed() validator { return nil } case models.MTOShipmentStatusApproved: - if isTIO || isTOO { + if isTIO || isTOO || isServiceCounselor { return nil } case models.MTOShipmentStatusCancellationRequested: diff --git a/pkg/services/mto_shipment/rules_test.go b/pkg/services/mto_shipment/rules_test.go index 2a3fd626117..546ac0be5f0 100644 --- a/pkg/services/mto_shipment/rules_test.go +++ b/pkg/services/mto_shipment/rules_test.go @@ -163,7 +163,7 @@ func (suite *MTOShipmentServiceSuite) TestUpdateValidations() { servicesCounselorSession, map[models.MTOShipmentStatus]bool{ models.MTOShipmentStatusSubmitted: true, - models.MTOShipmentStatusApproved: false, + models.MTOShipmentStatusApproved: true, models.MTOShipmentStatusCancellationRequested: false, models.MTOShipmentStatusCanceled: false, models.MTOShipmentStatusDiversionRequested: false, @@ -381,8 +381,8 @@ func (suite *MTOShipmentServiceSuite) TestDeleteValidations() { models.PPMShipmentStatusSubmitted: true, models.PPMShipmentStatusWaitingOnCustomer: false, models.PPMShipmentStatusNeedsAdvanceApproval: true, - models.PPMShipmentStatusNeedsPaymentApproval: true, - models.PPMShipmentStatusPaymentApproved: true, + models.PPMShipmentStatusNeedsCloseout: true, + models.PPMShipmentStatusCloseoutComplete: true, } for status, allowed := range testCases { diff --git a/pkg/services/mto_shipment/shipment_approver.go b/pkg/services/mto_shipment/shipment_approver.go index 529d90152e0..7a161d59fa3 100644 --- a/pkg/services/mto_shipment/shipment_approver.go +++ b/pkg/services/mto_shipment/shipment_approver.go @@ -1,6 +1,8 @@ package mtoshipment import ( + "math" + "github.com/gofrs/uuid" "github.com/pkg/errors" @@ -14,17 +16,19 @@ import ( ) type shipmentApprover struct { - router services.ShipmentRouter - siCreator services.MTOServiceItemCreator - planner route.Planner + router services.ShipmentRouter + siCreator services.MTOServiceItemCreator + planner route.Planner + moveWeights services.MoveWeights } // NewShipmentApprover creates a new struct with the service dependencies -func NewShipmentApprover(router services.ShipmentRouter, siCreator services.MTOServiceItemCreator, planner route.Planner) services.ShipmentApprover { +func NewShipmentApprover(router services.ShipmentRouter, siCreator services.MTOServiceItemCreator, planner route.Planner, moveWeights services.MoveWeights) services.ShipmentApprover { return &shipmentApprover{ router, siCreator, planner, + moveWeights, } } @@ -54,8 +58,25 @@ func (f *shipmentApprover) ApproveShipment(appCtx appcontext.AppContext, shipmen return nil, err } - transactionError := appCtx.NewTransaction(func(txnAppCtx appcontext.AppContext) error { + // if the shipment has an estimated weight at time of approval + // recalculate the authorized weight to include the newly authorized shipment + if shipment.PrimeEstimatedWeight != nil { + err = f.updateAuthorizedWeight(appCtx, shipment) + if err != nil { + return nil, err + } + + // changes to estimated weight need to run thecheck for excess weight + _, verrs, err := f.moveWeights.CheckExcessWeight(appCtx, shipment.MoveTaskOrderID, *shipment) + if verrs != nil && verrs.HasAny() { + return nil, errors.New(verrs.Error()) + } + if err != nil { + return nil, err + } + } + transactionError := appCtx.NewTransaction(func(txnAppCtx appcontext.AppContext) error { verrs, err := txnAppCtx.DB().ValidateAndSave(shipment) if verrs != nil && verrs.HasAny() { invalidInputError := apperror.NewInvalidInputError(shipment.ID, nil, verrs, "There was an issue with validating the updates") @@ -170,3 +191,41 @@ func (f *shipmentApprover) createShipmentServiceItems(appCtx appcontext.AppConte return nil } + +// when a TOO approves a shipment, if it was created by PRIME and an estimated weight exists +// add that to the authorized weight +func (f *shipmentApprover) updateAuthorizedWeight(appCtx appcontext.AppContext, shipment *models.MTOShipment) error { + var move models.Move + err := appCtx.DB().EagerPreload( + "MTOShipments", + "Orders.Entitlement", + ).Find(&move, shipment.MoveTaskOrderID) + + if err != nil { + return apperror.NewQueryError("Move", err, "unable to find Move") + } + + dBAuthorizedWeight := int(*shipment.PrimeEstimatedWeight) + if len(move.MTOShipments) != 0 { + for _, mtoShipment := range move.MTOShipments { + if mtoShipment.PrimeEstimatedWeight != nil && mtoShipment.Status == models.MTOShipmentStatusApproved && mtoShipment.ID != shipment.ID { + dBAuthorizedWeight += int(*mtoShipment.PrimeEstimatedWeight) + } + } + } + dBAuthorizedWeight = int(math.Round(float64(dBAuthorizedWeight) * 1.10)) + + entitlement := move.Orders.Entitlement + entitlement.DBAuthorizedWeight = &dBAuthorizedWeight + verrs, err := appCtx.DB().ValidateAndUpdate(entitlement) + + if verrs != nil && verrs.HasAny() { + invalidInputError := apperror.NewInvalidInputError(shipment.ID, nil, verrs, "There was an issue with validating the updates") + return invalidInputError + } + if err != nil { + return err + } + + return nil +} diff --git a/pkg/services/mto_shipment/shipment_approver_test.go b/pkg/services/mto_shipment/shipment_approver_test.go index bdf4a7f1605..ec3455de02a 100644 --- a/pkg/services/mto_shipment/shipment_approver_test.go +++ b/pkg/services/mto_shipment/shipment_approver_test.go @@ -1,6 +1,7 @@ package mtoshipment import ( + "math" "time" "github.com/gofrs/uuid" @@ -14,6 +15,7 @@ import ( "github.com/transcom/mymove/pkg/models" "github.com/transcom/mymove/pkg/route/mocks" "github.com/transcom/mymove/pkg/services" + "github.com/transcom/mymove/pkg/services/ghcrateengine" shipmentmocks "github.com/transcom/mymove/pkg/services/mocks" moverouter "github.com/transcom/mymove/pkg/services/move" mtoserviceitem "github.com/transcom/mymove/pkg/services/mto_service_item" @@ -30,6 +32,7 @@ type approveShipmentSubtestData struct { mockedShipmentApprover services.ShipmentApprover mockedShipmentRouter *shipmentmocks.ShipmentRouter reServiceCodes []models.ReServiceCode + moveWeights services.MoveWeights } // Creates data for the TestApproveShipment function @@ -87,16 +90,100 @@ func (suite *MTOShipmentServiceSuite) createApproveShipmentSubtestData() (subtes mock.Anything, mock.Anything, ).Return(400, nil) - siCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter) + 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.shipmentApprover = NewShipmentApprover(router, siCreator, subtestData.planner) - subtestData.mockedShipmentApprover = NewShipmentApprover(subtestData.mockedShipmentRouter, siCreator, subtestData.planner) + subtestData.shipmentApprover = NewShipmentApprover(router, siCreator, subtestData.planner, subtestData.moveWeights) + subtestData.mockedShipmentApprover = NewShipmentApprover(subtestData.mockedShipmentRouter, siCreator, subtestData.planner, subtestData.moveWeights) subtestData.appCtx = suite.AppContextWithSessionForTest(&auth.Session{ ApplicationName: auth.OfficeApp, OfficeUserID: uuid.Must(uuid.NewV4()), }) + const ( + dopTestServiceArea = "123" + dopTestWeight = 1212 + ) + + pickupAddress := factory.BuildAddress(suite.DB(), []factory.Customization{ + { + Model: models.Address{ + StreetAddress1: "7 Q St", + City: "Birmingham", + State: "KY", + PostalCode: "40356", + }, + }, + }, nil) + + //ContractCode + testdatagen.MakeReContractYear(suite.DB(), testdatagen.Assertions{ + ReContractYear: models.ReContractYear{ + StartDate: time.Now().Add(-24 * time.Hour), + EndDate: time.Now().Add(24 * time.Hour), + }, + }) + + contractYear, serviceArea, _, _ := testdatagen.SetupServiceAreaRateArea(suite.DB(), testdatagen.Assertions{ + ReDomesticServiceArea: models.ReDomesticServiceArea{ + ServiceArea: dopTestServiceArea, + }, + ReRateArea: models.ReRateArea{ + Name: "Alabama", + }, + ReZip3: models.ReZip3{ + Zip3: pickupAddress.PostalCode[0:3], + BasePointCity: pickupAddress.City, + State: pickupAddress.State, + }, + }) + + baseLinehaulPrice := testdatagen.MakeReDomesticLinehaulPrice(suite.DB(), testdatagen.Assertions{ + ReDomesticLinehaulPrice: models.ReDomesticLinehaulPrice{ + ContractID: contractYear.Contract.ID, + Contract: contractYear.Contract, + DomesticServiceAreaID: serviceArea.ID, + DomesticServiceArea: serviceArea, + IsPeakPeriod: false, + }, + }) + + _ = testdatagen.MakeReDomesticLinehaulPrice(suite.DB(), testdatagen.Assertions{ + ReDomesticLinehaulPrice: models.ReDomesticLinehaulPrice{ + ContractID: contractYear.Contract.ID, + Contract: contractYear.Contract, + DomesticServiceAreaID: serviceArea.ID, + DomesticServiceArea: serviceArea, + IsPeakPeriod: true, + PriceMillicents: baseLinehaulPrice.PriceMillicents - 2500, // minus $0.025 + }, + }) + + domesticOriginService := factory.FetchOrBuildReService(suite.DB(), []factory.Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeDOP, + Name: "Dom. Origin Price", + }, + }, + }, nil) + + domesticOriginPrice := models.ReDomesticServiceAreaPrice{ + ContractID: contractYear.Contract.ID, + ServiceID: domesticOriginService.ID, + IsPeakPeriod: true, + DomesticServiceAreaID: serviceArea.ID, + PriceCents: 146, + } + + domesticOriginPeakPrice := domesticOriginPrice + domesticOriginPeakPrice.PriceCents = 146 + + domesticOriginNonpeakPrice := domesticOriginPrice + domesticOriginNonpeakPrice.IsPeakPeriod = false + domesticOriginNonpeakPrice.PriceCents = 127 + return subtestData } @@ -107,6 +194,7 @@ func (suite *MTOShipmentServiceSuite) TestApproveShipment() { move := subtestData.move approver := subtestData.shipmentApprover planner := subtestData.planner + estimatedWeight := unit.Pound(1212) shipmentForAutoApprove := factory.BuildMTOShipment(appCtx.DB(), []factory.Customization{ { @@ -115,7 +203,9 @@ func (suite *MTOShipmentServiceSuite) TestApproveShipment() { }, { Model: models.MTOShipment{ - Status: models.MTOShipmentStatusSubmitted, + Status: models.MTOShipmentStatusSubmitted, + PrimeEstimatedWeight: &estimatedWeight, + RequestedPickupDate: &testdatagen.DateInsidePeakRateCycle, }, }, }, nil) @@ -126,6 +216,12 @@ func (suite *MTOShipmentServiceSuite) TestApproveShipment() { // Verify that required delivery date is not calculated when it does not need to be planner.AssertNumberOfCalls(suite.T(), "TransitDistance", 0) + planner.On("ZipTransitDistance", + mock.AnythingOfType("*appcontext.appContext"), + mock.Anything, + mock.Anything, + ).Return(500, nil) + preApprovalTime := time.Now() shipment, approverErr := approver.ApproveShipment(appCtx, shipmentForAutoApprove.ID, shipmentForAutoApproveEtag) @@ -152,6 +248,10 @@ func (suite *MTOShipmentServiceSuite) TestApproveShipment() { for i := range serviceItems { suite.Equal(models.MTOServiceItemStatusApproved, serviceItems[i].Status) suite.Equal(subtestData.reServiceCodes[i], serviceItems[i].ReService.Code) + if serviceItems[i].ReService.Code == models.ReServiceCodeDOP { + // pricing estimate will be nil for invalid service area + suite.Nil(serviceItems[i].PricingEstimate) + } } }) @@ -544,4 +644,80 @@ func (suite *MTOShipmentServiceSuite) TestApproveShipment() { suite.Equal(testCase.destinationLocation.PostalCode, TransitDistanceDestinationArg) } }) + suite.Run("Approval of a shipment with an estimated weight will update authorized weight", func() { + subtestData := suite.createApproveShipmentSubtestData() + appCtx := subtestData.appCtx + move := subtestData.move + planner := subtestData.planner + approver := subtestData.shipmentApprover + estimatedWeight := unit.Pound(1234) + shipment := factory.BuildMTOShipment(appCtx.DB(), []factory.Customization{ + { + Model: move, + LinkOnly: true, + }, + { + Model: models.MTOShipment{ + Status: models.MTOShipmentStatusSubmitted, + PrimeEstimatedWeight: &estimatedWeight, + }, + }, + }, nil) + + planner.On("ZipTransitDistance", + mock.AnythingOfType("*appcontext.appContext"), + mock.AnythingOfType("string"), + mock.AnythingOfType("string"), + ).Return(500, nil) + + suite.Equal(8000, *shipment.MoveTaskOrder.Orders.Entitlement.AuthorizedWeight()) + + shipmentEtag := etag.GenerateEtag(shipment.UpdatedAt) + + _, approverErr := approver.ApproveShipment(appCtx, shipment.ID, shipmentEtag) + suite.NoError(approverErr) + + err := appCtx.DB().Reload(shipment.MoveTaskOrder.Orders.Entitlement) + suite.NoError(err) + + estimatedWeight110 := int(math.Round(float64(*shipment.PrimeEstimatedWeight) * 1.10)) + suite.Equal(estimatedWeight110, *shipment.MoveTaskOrder.Orders.Entitlement.AuthorizedWeight()) + }) + + suite.Run("Approval of a shipment that exceeds excess weight will flag for excess weight", func() { + subtestData := suite.createApproveShipmentSubtestData() + appCtx := subtestData.appCtx + move := subtestData.move + planner := subtestData.planner + approver := subtestData.shipmentApprover + estimatedWeight := unit.Pound(100000) + shipment := factory.BuildMTOShipment(appCtx.DB(), []factory.Customization{ + { + Model: move, + LinkOnly: true, + }, + { + Model: models.MTOShipment{ + Status: models.MTOShipmentStatusSubmitted, + PrimeEstimatedWeight: &estimatedWeight, + }, + }, + }, nil) + + planner.On("ZipTransitDistance", + mock.AnythingOfType("*appcontext.appContext"), + mock.AnythingOfType("string"), + mock.AnythingOfType("string"), + ).Return(500, nil) + + shipmentEtag := etag.GenerateEtag(shipment.UpdatedAt) + + _, approverErr := approver.ApproveShipment(appCtx, shipment.ID, shipmentEtag) + suite.NoError(approverErr) + + err := appCtx.DB().Reload(&shipment.MoveTaskOrder) + suite.NoError(err) + + suite.NotNil(shipment.MoveTaskOrder.ExcessWeightQualifiedAt) + }) } diff --git a/pkg/services/mto_shipment/shipment_deleter_test.go b/pkg/services/mto_shipment/shipment_deleter_test.go index d85ba587e62..44cb952ea95 100644 --- a/pkg/services/mto_shipment/shipment_deleter_test.go +++ b/pkg/services/mto_shipment/shipment_deleter_test.go @@ -12,6 +12,7 @@ import ( "github.com/transcom/mymove/pkg/models" "github.com/transcom/mymove/pkg/models/roles" routemocks "github.com/transcom/mymove/pkg/route/mocks" + "github.com/transcom/mymove/pkg/services/ghcrateengine" moveservices "github.com/transcom/mymove/pkg/services/move" movetaskorder "github.com/transcom/mymove/pkg/services/move_task_order" mtoserviceitem "github.com/transcom/mymove/pkg/services/mto_service_item" @@ -29,7 +30,7 @@ func (suite *MTOShipmentServiceSuite) TestShipmentDeleter() { ).Return(400, nil) moveTaskOrderUpdater := movetaskorder.NewMoveTaskOrderUpdater( builder, - mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter), + mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), moveRouter, ) suite.Run("Returns an error when shipment is not found", func() { @@ -232,7 +233,7 @@ func (suite *MTOShipmentServiceSuite) TestPrimeShipmentDeleter() { ).Return(400, nil) moveTaskOrderUpdater := movetaskorder.NewMoveTaskOrderUpdater( builder, - mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter), + mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), moveRouter, ) suite.Run("Doesn't return an error when allowed to delete a shipment", func() { diff --git a/pkg/services/order/order_fetcher.go b/pkg/services/order/order_fetcher.go index f7dcf798ad6..0309a1056f5 100644 --- a/pkg/services/order/order_fetcher.go +++ b/pkg/services/order/order_fetcher.go @@ -157,11 +157,11 @@ func (f orderFetcher) ListOrders(appCtx appcontext.AppContext, officeUserID uuid if *params.NeedsPPMCloseout { query.InnerJoin("ppm_shipments", "ppm_shipments.shipment_id = mto_shipments.id"). LeftJoin("transportation_offices as closeout_to", "closeout_to.id = moves.closeout_office_id"). - Where("ppm_shipments.status IN (?)", models.PPMShipmentStatusWaitingOnCustomer, models.PPMShipmentStatusNeedsPaymentApproval, models.PPMShipmentStatusPaymentApproved). + Where("ppm_shipments.status IN (?)", models.PPMShipmentStatusWaitingOnCustomer, models.PPMShipmentStatusNeedsCloseout, models.PPMShipmentStatusCloseoutComplete). Where("service_members.affiliation NOT IN (?)", models.AffiliationNAVY, models.AffiliationMARINES, models.AffiliationCOASTGUARD) } else { query.LeftJoin("ppm_shipments", "ppm_shipments.shipment_id = mto_shipments.id"). - Where("(ppm_shipments.status IS NULL OR ppm_shipments.status NOT IN (?))", models.PPMShipmentStatusWaitingOnCustomer, models.PPMShipmentStatusNeedsPaymentApproval, models.PPMShipmentStatusPaymentApproved) + Where("(ppm_shipments.status IS NULL OR ppm_shipments.status NOT IN (?))", models.PPMShipmentStatusWaitingOnCustomer, models.PPMShipmentStatusNeedsCloseout, models.PPMShipmentStatusCloseoutComplete) } } else { if appCtx.Session().Roles.HasRole(roles.RoleTypeTOO) { @@ -471,11 +471,11 @@ func gblocFilterForPPMCloseoutForNavyMarineAndCG(gbloc *string) QueryOption { return func(query *pop.Query) { if gbloc != nil { if *gbloc == navyGbloc { - query.Where("mto_shipments.shipment_type = ? AND service_members.affiliation = ? AND ppm_shipments.status = ?", models.MTOShipmentTypePPM, models.AffiliationNAVY, models.PPMShipmentStatusNeedsPaymentApproval) + query.Where("mto_shipments.shipment_type = ? AND service_members.affiliation = ? AND ppm_shipments.status = ?", models.MTOShipmentTypePPM, models.AffiliationNAVY, models.PPMShipmentStatusNeedsCloseout) } else if *gbloc == tvcbGbloc { - query.Where("mto_shipments.shipment_type = ? AND service_members.affiliation = ? AND ppm_shipments.status = ?", models.MTOShipmentTypePPM, models.AffiliationMARINES, models.PPMShipmentStatusNeedsPaymentApproval) + query.Where("mto_shipments.shipment_type = ? AND service_members.affiliation = ? AND ppm_shipments.status = ?", models.MTOShipmentTypePPM, models.AffiliationMARINES, models.PPMShipmentStatusNeedsCloseout) } else if *gbloc == uscgGbloc { - query.Where("mto_shipments.shipment_type = ? AND service_members.affiliation = ? AND ppm_shipments.status = ?", models.MTOShipmentTypePPM, models.AffiliationCOASTGUARD, models.PPMShipmentStatusNeedsPaymentApproval) + query.Where("mto_shipments.shipment_type = ? AND service_members.affiliation = ? AND ppm_shipments.status = ?", models.MTOShipmentTypePPM, models.AffiliationCOASTGUARD, models.PPMShipmentStatusNeedsCloseout) } } } diff --git a/pkg/services/order/order_fetcher_test.go b/pkg/services/order/order_fetcher_test.go index a39b230f563..f5c614544d9 100644 --- a/pkg/services/order/order_fetcher_test.go +++ b/pkg/services/order/order_fetcher_test.go @@ -364,7 +364,7 @@ func (suite *OrderServiceSuite) TestListOrders() { // Expected outcome: search results should only include the move with the PPM type that was searched for officeUser, partialPPMMove, session := setupTestData() suite.Equal("PARTIAL", *partialPPMMove.PPMType) - ppmShipment := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), nil, []factory.Customization{ + ppmShipment := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), nil, []factory.Customization{ { Model: models.Move{ PPMType: models.StringPointer("FULL"), @@ -406,7 +406,7 @@ func (suite *OrderServiceSuite) TestListOrders() { }, }, }, nil) - ppmShipment := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), nil, []factory.Customization{ + ppmShipment := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), nil, []factory.Customization{ { Model: models.Move{ CloseoutOfficeID: &ftBragg.ID, @@ -434,7 +434,7 @@ func (suite *OrderServiceSuite) TestListOrders() { // Create a PPM submitted on April 1st closeoutInitiatedDate := time.Date(2022, 04, 01, 0, 0, 0, 0, time.UTC) - createdPPM := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), nil, []factory.Customization{ + createdPPM := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), nil, []factory.Customization{ { Model: models.PPMShipment{ SubmittedAt: &closeoutInitiatedDate, @@ -444,7 +444,7 @@ func (suite *OrderServiceSuite) TestListOrders() { // Create a PPM submitted on April 2nd closeoutInitiatedDate2 := time.Date(2022, 04, 02, 0, 0, 0, 0, time.UTC) - createdPPM2 := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), nil, []factory.Customization{ + createdPPM2 := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), nil, []factory.Customization{ { Model: models.PPMShipment{ SubmittedAt: &closeoutInitiatedDate2, @@ -472,7 +472,7 @@ func (suite *OrderServiceSuite) TestListOrders() { // Create a PPM submitted on April 1st closeoutInitiatedDate := time.Date(2022, 04, 01, 0, 0, 0, 0, time.UTC) - createdPPM := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), nil, []factory.Customization{ + createdPPM := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), nil, []factory.Customization{ { Model: models.PPMShipment{ SubmittedAt: &closeoutInitiatedDate, @@ -486,7 +486,7 @@ func (suite *OrderServiceSuite) TestListOrders() { { Model: models.PPMShipment{ SubmittedAt: &closeoutInitiatedDate2, - Status: models.PPMShipmentStatusNeedsPaymentApproval, + Status: models.PPMShipmentStatusNeedsCloseout, }, }, { @@ -593,7 +593,7 @@ func (suite *OrderServiceSuite) TestListOrdersPPMCloseoutForArmyAirforce() { factory.BuildMinimalPPMShipment(suite.DB(), []factory.Customization{ { Model: models.PPMShipment{ - Status: models.PPMShipmentStatusNeedsPaymentApproval, + Status: models.PPMShipmentStatusNeedsCloseout, }, }, { @@ -646,7 +646,7 @@ func (suite *OrderServiceSuite) TestListOrdersPPMCloseoutForArmyAirforce() { factory.BuildMinimalPPMShipment(suite.DB(), []factory.Customization{ { Model: models.PPMShipment{ - Status: models.PPMShipmentStatusNeedsPaymentApproval, + Status: models.PPMShipmentStatusNeedsCloseout, }, }, { @@ -683,7 +683,7 @@ func (suite *OrderServiceSuite) TestListOrdersPPMCloseoutForArmyAirforce() { factory.BuildMinimalPPMShipment(suite.DB(), []factory.Customization{ { Model: models.PPMShipment{ - Status: models.PPMShipmentStatusNeedsPaymentApproval, + Status: models.PPMShipmentStatusNeedsCloseout, }, }, { @@ -751,7 +751,7 @@ func (suite *OrderServiceSuite) TestListOrdersPPMCloseoutForNavyCoastGuardAndMar factory.BuildMinimalPPMShipment(suite.DB(), []factory.Customization{ { Model: models.PPMShipment{ - Status: models.PPMShipmentStatusNeedsPaymentApproval, + Status: models.PPMShipmentStatusNeedsCloseout, }, }, { @@ -777,7 +777,7 @@ func (suite *OrderServiceSuite) TestListOrdersPPMCloseoutForNavyCoastGuardAndMar factory.BuildMinimalPPMShipment(suite.DB(), []factory.Customization{ { Model: models.PPMShipment{ - Status: models.PPMShipmentStatusNeedsPaymentApproval, + Status: models.PPMShipmentStatusNeedsCloseout, }, }, { @@ -821,7 +821,7 @@ func (suite *OrderServiceSuite) TestListOrdersPPMCloseoutForNavyCoastGuardAndMar factory.BuildMinimalPPMShipment(suite.DB(), []factory.Customization{ { Model: models.PPMShipment{ - Status: models.PPMShipmentStatusNeedsPaymentApproval, + Status: models.PPMShipmentStatusNeedsCloseout, }, }, { @@ -846,7 +846,7 @@ func (suite *OrderServiceSuite) TestListOrdersPPMCloseoutForNavyCoastGuardAndMar factory.BuildMinimalPPMShipment(suite.DB(), []factory.Customization{ { Model: models.PPMShipment{ - Status: models.PPMShipmentStatusNeedsPaymentApproval, + Status: models.PPMShipmentStatusNeedsCloseout, }, }, { @@ -890,7 +890,7 @@ func (suite *OrderServiceSuite) TestListOrdersPPMCloseoutForNavyCoastGuardAndMar factory.BuildMinimalPPMShipment(suite.DB(), []factory.Customization{ { Model: models.PPMShipment{ - Status: models.PPMShipmentStatusNeedsPaymentApproval, + Status: models.PPMShipmentStatusNeedsCloseout, }, }, { @@ -915,7 +915,7 @@ func (suite *OrderServiceSuite) TestListOrdersPPMCloseoutForNavyCoastGuardAndMar factory.BuildMinimalPPMShipment(suite.DB(), []factory.Customization{ { Model: models.PPMShipment{ - Status: models.PPMShipmentStatusNeedsPaymentApproval, + Status: models.PPMShipmentStatusNeedsCloseout, }, }, { @@ -957,7 +957,7 @@ func (suite *OrderServiceSuite) TestListOrdersPPMCloseoutForNavyCoastGuardAndMar factory.BuildMinimalPPMShipment(suite.DB(), []factory.Customization{ { Model: models.PPMShipment{ - Status: models.PPMShipmentStatusPaymentApproved, + Status: models.PPMShipmentStatusCloseoutComplete, }, }, { @@ -1370,7 +1370,7 @@ func (suite *OrderServiceSuite) TestListOrdersNeedingServicesCounselingWithPPMCl }, }, nil) - ppm1 := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), nil, []factory.Customization{ + ppm1 := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), nil, []factory.Customization{ { Model: models.PPMShipment{ SubmittedAt: &closeoutInitiatedDate1, @@ -1385,7 +1385,7 @@ func (suite *OrderServiceSuite) TestListOrdersNeedingServicesCounselingWithPPMCl // Create a PPM submitted on April 2nd closeoutInitiatedDate2 := time.Date(2022, 04, 02, 0, 0, 0, 0, time.UTC) - ppm2 := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), nil, []factory.Customization{ + ppm2 := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), nil, []factory.Customization{ { Model: models.PPMShipment{ SubmittedAt: &closeoutInitiatedDate2, @@ -1432,7 +1432,7 @@ func (suite *OrderServiceSuite) TestListOrdersNeedingServicesCounselingWithPPMCl Name: "A", }, }}, nil) - ppmShipmentA := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), nil, []factory.Customization{ + ppmShipmentA := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), nil, []factory.Customization{ { Model: locationA, LinkOnly: true, @@ -1445,7 +1445,7 @@ func (suite *OrderServiceSuite) TestListOrdersNeedingServicesCounselingWithPPMCl Name: "B", }, }}, nil) - ppmShipmentB := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), nil, []factory.Customization{ + ppmShipmentB := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), nil, []factory.Customization{ { Model: locationB, LinkOnly: true, @@ -1494,7 +1494,7 @@ func (suite *OrderServiceSuite) TestListOrdersNeedingServicesCounselingWithPPMCl }, }, nil) - ppmShipmentA := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), nil, []factory.Customization{ + ppmShipmentA := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), nil, []factory.Customization{ { Model: dutyLocationA, LinkOnly: true, @@ -1513,7 +1513,7 @@ func (suite *OrderServiceSuite) TestListOrdersNeedingServicesCounselingWithPPMCl }, }, }, nil) - ppmShipmentB := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), nil, []factory.Customization{ + ppmShipmentB := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), nil, []factory.Customization{ { Model: dutyLocationB, LinkOnly: true, @@ -1558,7 +1558,7 @@ func (suite *OrderServiceSuite) TestListOrdersNeedingServicesCounselingWithPPMCl Model: models.TransportationOffice{Gbloc: "KKFA"}, }, }, nil) - ppmShipmentPartial := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), nil, []factory.Customization{ + ppmShipmentPartial := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), nil, []factory.Customization{ { Model: models.Move{ PPMType: models.StringPointer("Partial"), @@ -1570,7 +1570,7 @@ func (suite *OrderServiceSuite) TestListOrdersNeedingServicesCounselingWithPPMCl Type: &factory.TransportationOffices.CloseoutOffice, }, }) - ppmShipmentFull := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), nil, []factory.Customization{ + ppmShipmentFull := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), nil, []factory.Customization{ { Model: models.Move{ PPMType: models.StringPointer("FULL"), diff --git a/pkg/services/ppm_closeout/ppm_closeout.go b/pkg/services/ppm_closeout/ppm_closeout.go index cee6ca90bed..a0596151efa 100644 --- a/pkg/services/ppm_closeout/ppm_closeout.go +++ b/pkg/services/ppm_closeout/ppm_closeout.go @@ -212,6 +212,8 @@ func (p *ppmCloseoutFetcher) GetPPMShipment(appCtx appcontext.AppContext, ppmShi "FinalIncentive", "AdvanceAmountReceived", "Shipment.Distance", + "PickupAddress", + "DestinationAddress", ). Find(&ppmShipment, ppmShipmentID) @@ -224,8 +226,8 @@ func (p *ppmCloseoutFetcher) GetPPMShipment(appCtx appcontext.AppContext, ppmShi } } - // Check if PPM shipment is in "NEEDS_PAYMENT_APPROVAL" or "PAYMENT_APPROVED" status, if not, it's not ready for closeout - if ppmShipment.Status != models.PPMShipmentStatusNeedsPaymentApproval && ppmShipment.Status != models.PPMShipmentStatusPaymentApproved { + // Check if PPM shipment is in "NEEDS_CLOSEOUT" or "CLOSEOUT_COMPLETE" status, if not, it's not ready for closeout + if ppmShipment.Status != models.PPMShipmentStatusNeedsCloseout && ppmShipment.Status != models.PPMShipmentStatusCloseoutComplete { return nil, apperror.NewPPMNotReadyForCloseoutError(ppmShipmentID, "") } @@ -255,7 +257,7 @@ func (p *ppmCloseoutFetcher) GetExpenseStoragePrice(appCtx appcontext.AppContext } for _, movingExpense := range expenseItems { - if movingExpense.MovingExpenseType != nil && *movingExpense.MovingExpenseType == models.MovingExpenseReceiptTypeStorage { + if movingExpense.MovingExpenseType != nil && *movingExpense.MovingExpenseType == models.MovingExpenseReceiptTypeStorage && *movingExpense.Status == models.PPMDocumentStatusApproved { storageExpensePrice += *movingExpense.Amount } } diff --git a/pkg/services/ppm_closeout/ppm_closeout_test.go b/pkg/services/ppm_closeout/ppm_closeout_test.go index c0cb4af43a8..3b8996af2ba 100644 --- a/pkg/services/ppm_closeout/ppm_closeout_test.go +++ b/pkg/services/ppm_closeout/ppm_closeout_test.go @@ -71,6 +71,15 @@ func (suite *PPMCloseoutSuite) TestPPMShipmentCreator() { }, }) + testdatagen.FetchOrMakeReZip3(suite.AppContextForTest().DB(), testdatagen.Assertions{ + ReZip3: models.ReZip3{ + Contract: originDomesticServiceArea.Contract, + ContractID: originDomesticServiceArea.ContractID, + DomesticServiceArea: originDomesticServiceArea, + Zip3: "503", + }, + }) + testdatagen.FetchOrMakeReDomesticLinehaulPrice(suite.AppContextForTest().DB(), testdatagen.Assertions{ ReDomesticLinehaulPrice: models.ReDomesticLinehaulPrice{ Contract: originDomesticServiceArea.Contract, @@ -373,7 +382,7 @@ func (suite *PPMCloseoutSuite) TestPPMShipmentCreator() { suite.IsType(err, apperror.NotFoundError{}) }) - suite.Run("Returns a \"PPMNotReadyForCloseoutError\" if shipment is not marked as either \"NEEDS_PAYMENT_APPROVAL\" or \"APPROVED\"", func() { + suite.Run("Returns a \"PPMNotReadyForCloseoutError\" if shipment is not marked as either \"NEEDS_CLOSEOUT\" or \"APPROVED\"", func() { appCtx := suite.AppContextForTest() ppmShipment := suite.mockPPMShipmentForCloseoutTest(ppmBuildWaitingOnCustomer) ppmShipment.Status = models.PPMShipmentStatusSubmitted @@ -588,7 +597,7 @@ func (suite *PPMCloseoutSuite) mockPPMShipmentForCloseoutTest(buildType ppmBuild var ppmShipment models.PPMShipment if buildType == ppmBuildReadyForCloseout { - ppmShipment = factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.AppContextForTest().DB(), nil, ppmShipmentCustomization) + ppmShipment = factory.BuildPPMShipmentThatNeedsCloseout(suite.AppContextForTest().DB(), nil, ppmShipmentCustomization) } else if buildType == ppmBuildWaitingOnCustomer { ppmShipment = factory.BuildPPMShipment(suite.AppContextForTest().DB(), ppmShipmentCustomization, nil) } diff --git a/pkg/services/ppmshipment/payment_packet_creator_test.go b/pkg/services/ppmshipment/payment_packet_creator_test.go index e1919f7270d..d1c7a3cf375 100644 --- a/pkg/services/ppmshipment/payment_packet_creator_test.go +++ b/pkg/services/ppmshipment/payment_packet_creator_test.go @@ -66,7 +66,7 @@ func (suite *PPMShipmentSuite) TestCreatePaymentPacket() { suite.Run("generate pdf - INTERNAL", func() { - ppmShipment := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), userUploader, nil) + ppmShipment := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), userUploader, nil) // initial test data will have one trip(as trip #1) containing: // 1 empty weight with 1 doc // 1 full weight with 1 doc @@ -469,7 +469,7 @@ func (suite *PPMShipmentSuite) TestCreatePaymentPacket() { suite.Run("returns a ForbiddenError if the ppmShipment does not belong to user in INTERNAL context", func() { serviceMemberID := uuid.Must(uuid.NewV4()) - ppmShipment := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), userUploader, nil) + ppmShipment := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), userUploader, nil) appCtx := suite.AppContextWithSessionForTest(&auth.Session{ ServiceMemberID: serviceMemberID, ApplicationName: auth.MilApp, @@ -492,7 +492,7 @@ func (suite *PPMShipmentSuite) TestCreatePaymentPacket() { auth.AdminApp, } - ppmShipment := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), userUploader, nil) + ppmShipment := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), userUploader, nil) suite.NotNil(ppmShipment) notOwnerServiceMemberID := uuid.Must(uuid.NewV4()) @@ -535,7 +535,7 @@ func (suite *PPMShipmentSuite) TestCreatePaymentPacket() { }) suite.Run("generate with disabled bookmark and watermark", func() { - ppmShipment := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), userUploader, nil) + ppmShipment := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), userUploader, nil) suite.NotNil(ppmShipment) notOwnerServiceMemberID := uuid.Must(uuid.NewV4()) appCtx := suite.AppContextWithSessionForTest(&auth.Session{ @@ -556,7 +556,7 @@ func (suite *PPMShipmentSuite) TestCreatePaymentPacket() { }) suite.Run("generate with enable bookmark, disable watermark", func() { - ppmShipment := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), userUploader, nil) + ppmShipment := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), userUploader, nil) suite.NotNil(ppmShipment) notOwnerServiceMemberID := uuid.Must(uuid.NewV4()) appCtx := suite.AppContextWithSessionForTest(&auth.Session{ @@ -575,7 +575,7 @@ func (suite *PPMShipmentSuite) TestCreatePaymentPacket() { }) suite.Run("generate with disable bookmark, enable watermark", func() { - ppmShipment := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), userUploader, nil) + ppmShipment := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), userUploader, nil) suite.NotNil(ppmShipment) notOwnerServiceMemberID := uuid.Must(uuid.NewV4()) appCtx := suite.AppContextWithSessionForTest(&auth.Session{ diff --git a/pkg/services/ppmshipment/ppm_document_fetcher_test.go b/pkg/services/ppmshipment/ppm_document_fetcher_test.go index 29792e82c2a..8cc3b3456b3 100644 --- a/pkg/services/ppmshipment/ppm_document_fetcher_test.go +++ b/pkg/services/ppmshipment/ppm_document_fetcher_test.go @@ -24,7 +24,7 @@ func (suite *PPMShipmentSuite) TestPPMDocumentFetcher() { makePPMShipmentWithAllDocuments := func(appCtx appcontext.AppContext) *models.PPMShipment { // Set up PPM shipment that is at the correct stage of processing for when we would typically use this service - ppmShipment := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), userUploader, nil) + ppmShipment := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), userUploader, nil) suite.NotNil(ppmShipment) @@ -186,7 +186,7 @@ func (suite *PPMShipmentSuite) TestPPMDocumentFetcher() { // stage using our `utilities.SoftDestroy` function because of the related SignedCertification missing the // DeletedAt field, so we'll just set the PPMShipment.DeletedAt field directly. now := time.Now() - ppmShipmentToDelete := factory.BuildPPMShipmentThatNeedsPaymentApproval(appCtx.DB(), userUploader, []factory.Customization{ + ppmShipmentToDelete := factory.BuildPPMShipmentThatNeedsCloseout(appCtx.DB(), userUploader, []factory.Customization{ { Model: models.PPMShipment{ DeletedAt: &now, diff --git a/pkg/services/ppmshipment/ppm_estimator.go b/pkg/services/ppmshipment/ppm_estimator.go index 7ffaf4405fc..61f932684c2 100644 --- a/pkg/services/ppmshipment/ppm_estimator.go +++ b/pkg/services/ppmshipment/ppm_estimator.go @@ -50,8 +50,8 @@ func (f *estimatePPM) FinalIncentiveWithDefaultChecks(appCtx appcontext.AppConte func shouldSkipEstimatingIncentive(newPPMShipment *models.PPMShipment, oldPPMShipment *models.PPMShipment) bool { return oldPPMShipment.ExpectedDepartureDate.Equal(newPPMShipment.ExpectedDepartureDate) && - newPPMShipment.PickupPostalCode == oldPPMShipment.PickupPostalCode && - newPPMShipment.DestinationPostalCode == oldPPMShipment.DestinationPostalCode && + newPPMShipment.PickupAddress.PostalCode == oldPPMShipment.PickupAddress.PostalCode && + newPPMShipment.DestinationAddress.PostalCode == oldPPMShipment.DestinationAddress.PostalCode && ((newPPMShipment.EstimatedWeight == nil && oldPPMShipment.EstimatedWeight == nil) || (oldPPMShipment.EstimatedWeight != nil && newPPMShipment.EstimatedWeight.Int() == oldPPMShipment.EstimatedWeight.Int())) } @@ -97,8 +97,8 @@ func shouldCalculateSITCost(newPPMShipment *models.PPMShipment, oldPPMShipment * *newPPMShipment.SITEstimatedWeight != *oldPPMShipment.SITEstimatedWeight || *newPPMShipment.SITEstimatedEntryDate != *oldPPMShipment.SITEstimatedEntryDate || *newPPMShipment.SITEstimatedDepartureDate != *oldPPMShipment.SITEstimatedDepartureDate || - newPPMShipment.PickupPostalCode != oldPPMShipment.PickupPostalCode || - newPPMShipment.DestinationPostalCode != oldPPMShipment.DestinationPostalCode || + newPPMShipment.PickupAddress.PostalCode != oldPPMShipment.PickupAddress.PostalCode || + newPPMShipment.DestinationAddress.PostalCode != oldPPMShipment.DestinationAddress.PostalCode || newPPMShipment.ExpectedDepartureDate != oldPPMShipment.ExpectedDepartureDate } @@ -161,7 +161,7 @@ func (f *estimatePPM) estimateIncentive(appCtx appcontext.AppContext, oldPPMShip } func (f *estimatePPM) finalIncentive(appCtx appcontext.AppContext, oldPPMShipment models.PPMShipment, newPPMShipment *models.PPMShipment, checks ...ppmShipmentValidator) (*unit.Cents, error) { - if newPPMShipment.Status != models.PPMShipmentStatusWaitingOnCustomer && newPPMShipment.Status != models.PPMShipmentStatusNeedsPaymentApproval { + if newPPMShipment.Status != models.PPMShipmentStatusWaitingOnCustomer && newPPMShipment.Status != models.PPMShipmentStatusNeedsCloseout { return oldPPMShipment.FinalIncentive, nil } @@ -394,9 +394,9 @@ func priceFirstDaySIT(appCtx appcontext.AppContext, pricer services.ParamsPricer return nil, errors.New("ppm estimate pricer for SIT service item does not implement the first day pricer interface") } - serviceAreaPostalCode := ppmShipment.PickupPostalCode + serviceAreaPostalCode := ppmShipment.PickupAddress.PostalCode if serviceItem.ReService.Code == models.ReServiceCodeDDFSIT { - serviceAreaPostalCode = ppmShipment.DestinationPostalCode + serviceAreaPostalCode = ppmShipment.DestinationAddress.PostalCode } serviceAreaLookup := serviceparamvaluelookups.ServiceAreaLookup{ @@ -433,9 +433,9 @@ func priceAdditionalDaySIT(appCtx appcontext.AppContext, pricer services.ParamsP return nil, errors.New("ppm estimate pricer for SIT service item does not implement the additional days pricer interface") } - serviceAreaPostalCode := ppmShipment.PickupPostalCode + serviceAreaPostalCode := ppmShipment.PickupAddress.PostalCode if serviceItem.ReService.Code == models.ReServiceCodeDDASIT { - serviceAreaPostalCode = ppmShipment.DestinationPostalCode + serviceAreaPostalCode = ppmShipment.DestinationAddress.PostalCode } serviceAreaLookup := serviceparamvaluelookups.ServiceAreaLookup{ Address: models.Address{PostalCode: serviceAreaPostalCode}, @@ -462,8 +462,8 @@ func MapPPMShipmentEstimatedFields(ppmShipment models.PPMShipment) models.MTOShi ppmShipment.Shipment.ActualPickupDate = &ppmShipment.ExpectedDepartureDate ppmShipment.Shipment.RequestedPickupDate = &ppmShipment.ExpectedDepartureDate - ppmShipment.Shipment.PickupAddress = &models.Address{PostalCode: ppmShipment.PickupPostalCode} - ppmShipment.Shipment.DestinationAddress = &models.Address{PostalCode: ppmShipment.DestinationPostalCode} + ppmShipment.Shipment.PickupAddress = &models.Address{PostalCode: ppmShipment.PickupAddress.PostalCode} + ppmShipment.Shipment.DestinationAddress = &models.Address{PostalCode: ppmShipment.DestinationAddress.PostalCode} ppmShipment.Shipment.PrimeActualWeight = ppmShipment.EstimatedWeight return ppmShipment.Shipment diff --git a/pkg/services/ppmshipment/ppm_estimator_test.go b/pkg/services/ppmshipment/ppm_estimator_test.go index 1689846417e..ef1c3a4262c 100644 --- a/pkg/services/ppmshipment/ppm_estimator_test.go +++ b/pkg/services/ppmshipment/ppm_estimator_test.go @@ -180,6 +180,15 @@ func (suite *PPMShipmentSuite) TestPPMEstimator() { }, }) + testdatagen.FetchOrMakeReZip3(suite.DB(), testdatagen.Assertions{ + ReZip3: models.ReZip3{ + Contract: originDomesticServiceArea.Contract, + ContractID: originDomesticServiceArea.ContractID, + DomesticServiceArea: originDomesticServiceArea, + Zip3: "503", + }, + }) + testdatagen.FetchOrMakeReZip3(suite.DB(), testdatagen.Assertions{ ReZip3: models.ReZip3{ Contract: originDomesticServiceArea.Contract, @@ -488,16 +497,16 @@ func (suite *PPMShipmentSuite) TestPPMEstimator() { // DTOD distance is going to be less than the HHG Rand McNally distance of 2361 miles mockedPlanner.On("ZipTransitDistance", mock.AnythingOfType("*appcontext.appContext"), - "90210", "30813").Return(2294, nil) + "50309", "30813").Return(2294, nil) ppmEstimate, _, err := ppmEstimator.EstimateIncentiveWithDefaultChecks(suite.AppContextForTest(), oldPPMShipment, &newPPM) suite.NilOrNoVerrs(err) mockedPlanner.AssertCalled(suite.T(), "ZipTransitDistance", mock.AnythingOfType("*appcontext.appContext"), - "90210", "30813") + "50309", "30813") mockedPaymentRequestHelper.AssertCalled(suite.T(), "FetchServiceParamsForServiceItems", mock.AnythingOfType("*appcontext.appContext"), mock.AnythingOfType("[]models.MTOServiceItem")) - suite.Equal(oldPPMShipment.PickupPostalCode, newPPM.PickupPostalCode) + suite.Equal(oldPPMShipment.PickupAddress.PostalCode, newPPM.PickupAddress.PostalCode) suite.Equal(unit.Pound(5000), *newPPM.EstimatedWeight) suite.Equal(unit.Cents(70064364), *ppmEstimate) }) @@ -524,7 +533,7 @@ func (suite *PPMShipmentSuite) TestPPMEstimator() { // DTOD distance is going to be less than the HHG Rand McNally distance of 2361 miles mockedPlanner.On("ZipTransitDistance", mock.AnythingOfType("*appcontext.appContext"), - "90210", "30813").Return(2294, nil).Once() + "50309", "30813").Return(2294, nil).Once() ppmEstimate, _, err := ppmEstimator.EstimateIncentiveWithDefaultChecks(suite.AppContextForTest(), oldPPMShipment, &newPPM) suite.NilOrNoVerrs(err) @@ -547,9 +556,9 @@ func (suite *PPMShipmentSuite) TestPPMEstimator() { estimatedIncentive, _, err := ppmEstimator.EstimateIncentiveWithDefaultChecks(suite.AppContextForTest(), oldPPMShipment, &newPPM) suite.NilOrNoVerrs(err) - suite.Equal(oldPPMShipment.PickupPostalCode, newPPM.PickupPostalCode) + suite.Equal(oldPPMShipment.PickupAddress.PostalCode, newPPM.PickupAddress.PostalCode) suite.Equal(*oldPPMShipment.EstimatedWeight, *newPPM.EstimatedWeight) - suite.Equal(oldPPMShipment.DestinationPostalCode, newPPM.DestinationPostalCode) + suite.Equal(oldPPMShipment.DestinationAddress.PostalCode, newPPM.DestinationAddress.PostalCode) suite.True(oldPPMShipment.ExpectedDepartureDate.Equal(newPPM.ExpectedDepartureDate)) suite.Equal(*oldPPMShipment.EstimatedIncentive, *estimatedIncentive) suite.Equal(models.BoolPointer(true), newPPM.HasRequestedAdvance) @@ -564,13 +573,16 @@ func (suite *PPMShipmentSuite) TestPPMEstimator() { }, }, }, nil) + + pickupAddress := models.Address{PostalCode: oldPPMShipment.PickupAddress.PostalCode} + destinationAddress := models.Address{PostalCode: "94040"} newPPM := models.PPMShipment{ ID: uuid.FromStringOrNil("575c25aa-b4eb-4024-9597-43483003c773"), ShipmentID: oldPPMShipment.ShipmentID, - Status: models.PPMShipmentStatusPaymentApproved, + Status: models.PPMShipmentStatusCloseoutComplete, ExpectedDepartureDate: oldPPMShipment.ExpectedDepartureDate, - PickupPostalCode: oldPPMShipment.PickupPostalCode, - DestinationPostalCode: "94040", + PickupAddress: &pickupAddress, + DestinationAddress: &destinationAddress, EstimatedWeight: oldPPMShipment.EstimatedWeight, SITExpected: oldPPMShipment.SITExpected, EstimatedIncentive: models.CentPointer(unit.Cents(600000)), @@ -585,7 +597,7 @@ func (suite *PPMShipmentSuite) TestPPMEstimator() { oldPPMShipment := factory.BuildMinimalPPMShipment(suite.DB(), nil, nil) newPPM := oldPPMShipment - newPPM.DestinationPostalCode = "94040" + newPPM.DestinationAddress.PostalCode = "94040" _, _, err := ppmEstimator.EstimateIncentiveWithDefaultChecks(suite.AppContextForTest(), oldPPMShipment, &newPPM) suite.NoError(err) suite.Nil(newPPM.EstimatedIncentive) @@ -600,7 +612,7 @@ func (suite *PPMShipmentSuite) TestPPMEstimator() { oldPPMShipment := factory.BuildPPMShipment(suite.DB(), []factory.Customization{ { Model: models.PPMShipment{ - ActualPickupPostalCode: models.StringPointer("90210"), + ActualPickupPostalCode: models.StringPointer("50309"), ActualDestinationPostalCode: models.StringPointer("30813"), ActualMoveDate: models.TimePointer(actualMoveDate), Status: models.PPMShipmentStatusWaitingOnCustomer, @@ -629,13 +641,13 @@ func (suite *PPMShipmentSuite) TestPPMEstimator() { // DTOD distance is going to be less than the HHG Rand McNally distance of 2361 miles mockedPlanner.On("ZipTransitDistance", mock.AnythingOfType("*appcontext.appContext"), - "90210", "30813").Return(2294, nil) + "50309", "30813").Return(2294, nil) ppmFinal, err := ppmEstimator.FinalIncentiveWithDefaultChecks(suite.AppContextForTest(), oldPPMShipment, &newPPM) suite.NilOrNoVerrs(err) mockedPlanner.AssertCalled(suite.T(), "ZipTransitDistance", mock.AnythingOfType("*appcontext.appContext"), - "90210", "30813") + "50309", "30813") mockedPaymentRequestHelper.AssertCalled(suite.T(), "FetchServiceParamsForServiceItems", mock.AnythingOfType("*appcontext.appContext"), mock.AnythingOfType("[]models.MTOServiceItem")) suite.Equal(oldPPMShipment.ActualPickupPostalCode, newPPM.ActualPickupPostalCode) @@ -652,7 +664,7 @@ func (suite *PPMShipmentSuite) TestPPMEstimator() { oldPPMShipment := factory.BuildPPMShipment(suite.DB(), []factory.Customization{ { Model: models.PPMShipment{ - ActualPickupPostalCode: models.StringPointer("90210"), + ActualPickupPostalCode: models.StringPointer("50309"), ActualDestinationPostalCode: models.StringPointer("30813"), ActualMoveDate: models.TimePointer(moveDate), Status: models.PPMShipmentStatusWaitingOnCustomer, @@ -683,13 +695,13 @@ func (suite *PPMShipmentSuite) TestPPMEstimator() { // DTOD distance is going to be less than the HHG Rand McNally distance of 2361 miles mockedPlanner.On("ZipTransitDistance", mock.AnythingOfType("*appcontext.appContext"), - "90210", "30813").Return(2294, nil) + "50309", "30813").Return(2294, nil) ppmFinal, err := ppmEstimator.FinalIncentiveWithDefaultChecks(suite.AppContextForTest(), oldPPMShipment, &newPPM) suite.NilOrNoVerrs(err) mockedPlanner.AssertCalled(suite.T(), "ZipTransitDistance", mock.AnythingOfType("*appcontext.appContext"), - "90210", "30813") + "50309", "30813") mockedPaymentRequestHelper.AssertCalled(suite.T(), "FetchServiceParamsForServiceItems", mock.AnythingOfType("*appcontext.appContext"), mock.AnythingOfType("[]models.MTOServiceItem")) suite.Equal(oldPPMShipment.ActualPickupPostalCode, newPPM.ActualPickupPostalCode) @@ -705,10 +717,10 @@ func (suite *PPMShipmentSuite) TestPPMEstimator() { oldEmptyWeight := unit.Pound(6000) oldFullWeight := unit.Pound(10000) moveDate := time.Date(2020, time.March, 15, 0, 0, 0, 0, time.UTC) - oldPPMShipment := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), nil, []factory.Customization{ + oldPPMShipment := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), nil, []factory.Customization{ { Model: models.PPMShipment{ - ActualPickupPostalCode: models.StringPointer("90210"), + ActualPickupPostalCode: models.StringPointer("50309"), ActualDestinationPostalCode: models.StringPointer("30813"), ActualMoveDate: models.TimePointer(moveDate), }, @@ -740,13 +752,13 @@ func (suite *PPMShipmentSuite) TestPPMEstimator() { // DTOD distance is going to be less than the HHG Rand McNally distance of 2361 miles mockedPlanner.On("ZipTransitDistance", mock.AnythingOfType("*appcontext.appContext"), - "90210", "30813").Return(2294, nil) + "50309", "30813").Return(2294, nil) ppmFinal, err := ppmEstimator.FinalIncentiveWithDefaultChecks(suite.AppContextForTest(), oldPPMShipment, &newPPM) suite.NilOrNoVerrs(err) mockedPlanner.AssertCalled(suite.T(), "ZipTransitDistance", mock.AnythingOfType("*appcontext.appContext"), - "90210", "30813") + "50309", "30813") mockedPaymentRequestHelper.AssertCalled(suite.T(), "FetchServiceParamsForServiceItems", mock.AnythingOfType("*appcontext.appContext"), mock.AnythingOfType("[]models.MTOServiceItem")) originalWeight, newWeight := SumWeightTickets(oldPPMShipment, newPPM) @@ -760,7 +772,7 @@ func (suite *PPMShipmentSuite) TestPPMEstimator() { oldFullWeight := unit.Pound(10000) oldEmptyWeight := unit.Pound(6000) moveDate := time.Date(2020, time.March, 15, 0, 0, 0, 0, time.UTC) - oldPPMShipment := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), nil, []factory.Customization{ + oldPPMShipment := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), nil, []factory.Customization{ { Model: models.PPMShipment{ ActualPickupPostalCode: models.StringPointer("90210"), @@ -823,7 +835,7 @@ func (suite *PPMShipmentSuite) TestPPMEstimator() { oldFullWeight := unit.Pound(10000) oldEmptyWeight := unit.Pound(6000) moveDate := time.Date(2020, time.March, 15, 0, 0, 0, 0, time.UTC) - oldPPMShipment := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), nil, []factory.Customization{ + oldPPMShipment := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), nil, []factory.Customization{ { Model: models.PPMShipment{ ActualPickupPostalCode: models.StringPointer("90210"), @@ -892,7 +904,7 @@ func (suite *PPMShipmentSuite) TestPPMEstimator() { oldFullWeight := unit.Pound(10000) oldEmptyWeight := unit.Pound(6000) moveDate := time.Date(2020, time.March, 15, 0, 0, 0, 0, time.UTC) - oldPPMShipment := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), nil, []factory.Customization{ + oldPPMShipment := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), nil, []factory.Customization{ { Model: models.PPMShipment{ ActualPickupPostalCode: models.StringPointer("90210"), @@ -930,7 +942,7 @@ func (suite *PPMShipmentSuite) TestPPMEstimator() { oldFullWeight := unit.Pound(10000) oldEmptyWeight := unit.Pound(6000) moveDate := time.Date(2020, time.March, 15, 0, 0, 0, 0, time.UTC) - oldPPMShipment := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), nil, []factory.Customization{ + oldPPMShipment := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), nil, []factory.Customization{ { Model: models.PPMShipment{ ActualPickupPostalCode: models.StringPointer("90210"), @@ -979,7 +991,7 @@ func (suite *PPMShipmentSuite) TestPPMEstimator() { oldEmptyWeight := unit.Pound(6000) rejected := models.PPMDocumentStatusRejected moveDate := time.Date(2020, time.March, 15, 0, 0, 0, 0, time.UTC) - oldPPMShipment := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), nil, []factory.Customization{ + oldPPMShipment := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), nil, []factory.Customization{ { Model: models.PPMShipment{ ActualPickupPostalCode: models.StringPointer("90210"), @@ -1029,7 +1041,7 @@ func (suite *PPMShipmentSuite) TestPPMEstimator() { oldFullWeight := unit.Pound(10000) oldEmptyWeight := unit.Pound(6000) moveDate := time.Date(2020, time.March, 15, 0, 0, 0, 0, time.UTC) - oldPPMShipment := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), nil, []factory.Customization{ + oldPPMShipment := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), nil, []factory.Customization{ { Model: models.PPMShipment{ ActualPickupPostalCode: models.StringPointer("90210"), @@ -1084,7 +1096,7 @@ func (suite *PPMShipmentSuite) TestPPMEstimator() { oldFullWeight := unit.Pound(10000) oldEmptyWeight := unit.Pound(6000) moveDate := time.Date(2020, time.March, 15, 0, 0, 0, 0, time.UTC) - oldPPMShipment := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), nil, []factory.Customization{ + oldPPMShipment := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), nil, []factory.Customization{ { Model: models.PPMShipment{ ActualPickupPostalCode: models.StringPointer("90210"), @@ -1140,7 +1152,7 @@ func (suite *PPMShipmentSuite) TestPPMEstimator() { oldFullWeight := unit.Pound(10000) oldEmptyWeight := unit.Pound(6000) moveDate := time.Date(2020, time.March, 15, 0, 0, 0, 0, time.UTC) - oldPPMShipment := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), nil, []factory.Customization{ + oldPPMShipment := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), nil, []factory.Customization{ { Model: models.PPMShipment{ ActualPickupPostalCode: models.StringPointer("90210"), @@ -1174,7 +1186,7 @@ func (suite *PPMShipmentSuite) TestPPMEstimator() { oldFullWeight := unit.Pound(10000) oldEmptyWeight := unit.Pound(6000) moveDate := time.Date(2020, time.March, 15, 0, 0, 0, 0, time.UTC) - oldPPMShipment := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), nil, []factory.Customization{ + oldPPMShipment := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), nil, []factory.Customization{ { Model: models.PPMShipment{ ActualPickupPostalCode: models.StringPointer("90210"), @@ -1216,7 +1228,7 @@ func (suite *PPMShipmentSuite) TestPPMEstimator() { oldFullWeight := unit.Pound(10000) oldEmptyWeight := unit.Pound(6000) moveDate := time.Date(2020, time.March, 15, 0, 0, 0, 0, time.UTC) - oldPPMShipment := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), nil, []factory.Customization{ + oldPPMShipment := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), nil, []factory.Customization{ { Model: models.PPMShipment{ ActualPickupPostalCode: models.StringPointer("90210"), @@ -1300,7 +1312,7 @@ func (suite *PPMShipmentSuite) TestPPMEstimator() { }, nil) newPPM := oldPPMShipment - newPPM.Status = models.PPMShipmentStatusPaymentApproved + newPPM.Status = models.PPMShipmentStatusCloseoutComplete finalIncentive, err := ppmEstimator.FinalIncentiveWithDefaultChecks(suite.AppContextForTest(), oldPPMShipment, &newPPM) suite.NilOrNoVerrs(err) @@ -1349,6 +1361,7 @@ func (suite *PPMShipmentSuite) TestPPMEstimator() { }, }, }, nil) + shipmentOriginSIT := factory.BuildPPMShipment(nil, []factory.Customization{ { Model: models.PPMShipment{ @@ -1367,7 +1380,7 @@ func (suite *PPMShipmentSuite) TestPPMEstimator() { }, nil) mockedPlanner.On("ZipTransitDistance", mock.AnythingOfType("*appcontext.appContext"), - "90210", "30813").Return(2294, nil) + "50309", "30813").Return(2294, nil) _, estimatedSITCost, err := ppmEstimator.EstimateIncentiveWithDefaultChecks(suite.AppContextForTest(), models.PPMShipment{}, &shipmentOriginSIT) @@ -1406,7 +1419,7 @@ func (suite *PPMShipmentSuite) TestPPMEstimator() { }, nil) mockedPlanner.On("ZipTransitDistance", mock.AnythingOfType("*appcontext.appContext"), - "90210", "30813").Return(2294, nil) + "50309", "30813").Return(2294, nil) _, estimatedSITCost, err := ppmEstimator.EstimateIncentiveWithDefaultChecks(suite.AppContextForTest(), models.PPMShipment{}, &shipmentOriginSIT) @@ -1427,6 +1440,7 @@ func (suite *PPMShipmentSuite) TestPPMEstimator() { }, }, }, nil) + shipmentOriginSIT := factory.BuildPPMShipment(nil, []factory.Customization{ { Model: models.PPMShipment{ @@ -1444,7 +1458,7 @@ func (suite *PPMShipmentSuite) TestPPMEstimator() { }, }, nil) mockedPlanner.On("ZipTransitDistance", mock.AnythingOfType("*appcontext.appContext"), - "90210", "30813").Return(2294, nil) + "50309", "30813").Return(2294, nil) _, estimatedSITCost, err := ppmEstimator.EstimateIncentiveWithDefaultChecks(suite.AppContextForTest(), models.PPMShipment{}, &shipmentOriginSIT) @@ -1591,10 +1605,26 @@ func (suite *PPMShipmentSuite) TestPPMEstimator() { }, nil) // PPM base shipment field changes will affect SIT pricing shipmentDifferentPickup := originalShipment - shipmentDifferentPickup.PickupPostalCode = "90211" + pickupAddress := models.Address{ + StreetAddress1: originalShipment.PickupAddress.StreetAddress1, + StreetAddress2: originalShipment.PickupAddress.StreetAddress2, + StreetAddress3: originalShipment.PickupAddress.StreetAddress3, + City: originalShipment.PickupAddress.City, + State: originalShipment.PickupAddress.State, + PostalCode: "90211", + } + shipmentDifferentPickup.PickupAddress = &pickupAddress shipmentDifferentDestination := originalShipment - shipmentDifferentDestination.DestinationPostalCode = "30814" + destinationAddress := models.Address{ + StreetAddress1: originalShipment.PickupAddress.StreetAddress1, + StreetAddress2: originalShipment.PickupAddress.StreetAddress2, + StreetAddress3: originalShipment.PickupAddress.StreetAddress3, + City: originalShipment.PickupAddress.City, + State: originalShipment.PickupAddress.State, + PostalCode: "30814", + } + shipmentDifferentDestination.DestinationAddress = &destinationAddress shipmentDifferentDeparture := originalShipment // original date was Mar 15th so adding 3 months should affect the date peak period pricing @@ -1604,7 +1634,7 @@ func (suite *PPMShipmentSuite) TestPPMEstimator() { "90211", "30813").Return(2294, nil) mockedPlanner.On("ZipTransitDistance", mock.AnythingOfType("*appcontext.appContext"), - "90210", "30814").Return(2290, nil) + "50309", "30814").Return(2290, nil) // SIT specific field changes will likely cause the price to change, although adjusting dates may not change // the total number of days in SIT. diff --git a/pkg/services/ppmshipment/ppm_shipment_fetcher_test.go b/pkg/services/ppmshipment/ppm_shipment_fetcher_test.go index b6b9cd83c2e..cc62610f3cf 100644 --- a/pkg/services/ppmshipment/ppm_shipment_fetcher_test.go +++ b/pkg/services/ppmshipment/ppm_shipment_fetcher_test.go @@ -637,7 +637,7 @@ func (suite *PPMShipmentSuite) TestPPMShipmentFetcher() { } suite.Run("Excludes deleted uploads", func() { - ppmShipment := factory.BuildPPMShipmentThatNeedsPaymentApprovalWithAllDocTypes( + ppmShipment := factory.BuildPPMShipmentThatNeedsCloseoutWithAllDocTypes( suite.DB(), userUploader, ) diff --git a/pkg/services/ppmshipment/ppm_shipment_new_submitter_test.go b/pkg/services/ppmshipment/ppm_shipment_new_submitter_test.go index 77089eac1e3..f6c81b95100 100644 --- a/pkg/services/ppmshipment/ppm_shipment_new_submitter_test.go +++ b/pkg/services/ppmshipment/ppm_shipment_new_submitter_test.go @@ -215,7 +215,7 @@ func (suite *PPMShipmentSuite) TestSubmitNewCustomerCloseOut() { router := setUpPPMShipperRouterMock( func(_ appcontext.AppContext, ppmShipment *models.PPMShipment) error { - ppmShipment.Status = models.PPMShipmentStatusNeedsPaymentApproval + ppmShipment.Status = models.PPMShipmentStatusNeedsCloseout return nil }) @@ -239,7 +239,7 @@ func (suite *PPMShipmentSuite) TestSubmitNewCustomerCloseOut() { ) if suite.NoError(err) && suite.NotNil(updatedPPMShipment) { - suite.Equal(models.PPMShipmentStatusNeedsPaymentApproval, updatedPPMShipment.Status) + suite.Equal(models.PPMShipmentStatusNeedsCloseout, updatedPPMShipment.Status) if suite.NotNil(updatedPPMShipment.SignedCertification) { suite.Equal(newSignedCertification.ID, updatedPPMShipment.SignedCertification.ID) diff --git a/pkg/services/ppmshipment/ppm_shipment_review_documents_test.go b/pkg/services/ppmshipment/ppm_shipment_review_documents_test.go index 0c591f1d6cc..245b155befc 100644 --- a/pkg/services/ppmshipment/ppm_shipment_review_documents_test.go +++ b/pkg/services/ppmshipment/ppm_shipment_review_documents_test.go @@ -67,7 +67,7 @@ func (suite *PPMShipmentSuite) TestReviewDocuments() { }) suite.Run("Returns an error if submitting the close out documentation fails", func() { - existingPPMShipment := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), nil, nil) + existingPPMShipment := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), nil, nil) appCtx := suite.AppContextWithSessionForTest(&auth.Session{ UserID: existingPPMShipment.Shipment.MoveTaskOrder.Orders.ServiceMember.UserID, @@ -77,7 +77,7 @@ func (suite *PPMShipmentSuite) TestReviewDocuments() { existingPPMShipment.ID, fmt.Sprintf( "PPM shipment documents cannot be submitted because it's not in the %s status.", - models.PPMShipmentStatusNeedsPaymentApproval, + models.PPMShipmentStatusNeedsCloseout, ), ) @@ -99,7 +99,7 @@ func (suite *PPMShipmentSuite) TestReviewDocuments() { }) suite.Run("Can route the PPMShipment properly", func() { - existingPPMShipment := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), nil, nil) + existingPPMShipment := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), nil, nil) appCtx := suite.AppContextWithSessionForTest(&auth.Session{ UserID: existingPPMShipment.Shipment.MoveTaskOrder.Orders.ServiceMember.UserID, @@ -107,7 +107,7 @@ func (suite *PPMShipmentSuite) TestReviewDocuments() { router := setUpPPMShipperRouterMock( func(_ appcontext.AppContext, ppmShipment *models.PPMShipment) error { - ppmShipment.Status = models.PPMShipmentStatusPaymentApproved + ppmShipment.Status = models.PPMShipmentStatusCloseoutComplete return nil }) @@ -124,7 +124,7 @@ func (suite *PPMShipmentSuite) TestReviewDocuments() { ) if suite.NoError(err) && suite.NotNil(updatedPPMShipment) { - suite.Equal(models.PPMShipmentStatusPaymentApproved, updatedPPMShipment.Status) + suite.Equal(models.PPMShipmentStatusCloseoutComplete, updatedPPMShipment.Status) router.(*mocks.PPMShipmentRouter).AssertCalled( suite.T(), diff --git a/pkg/services/ppmshipment/ppm_shipment_router.go b/pkg/services/ppmshipment/ppm_shipment_router.go index f67c474b2cf..67291d4a487 100644 --- a/pkg/services/ppmshipment/ppm_shipment_router.go +++ b/pkg/services/ppmshipment/ppm_shipment_router.go @@ -65,14 +65,14 @@ func (p *ppmShipmentRouter) Submit(appCtx appcontext.AppContext, ppmShipment *mo // SendToCustomer sets the PPM shipment to the WAITING_ON_CUSTOMER status func (p *ppmShipmentRouter) SendToCustomer(appCtx appcontext.AppContext, ppmShipment *models.PPMShipment) error { - if ppmShipment.Status != models.PPMShipmentStatusSubmitted && ppmShipment.Status != models.PPMShipmentStatusNeedsPaymentApproval { + if ppmShipment.Status != models.PPMShipmentStatusSubmitted && ppmShipment.Status != models.PPMShipmentStatusNeedsCloseout { return apperror.NewConflictError( ppmShipment.ID, fmt.Sprintf( "PPM shipment can't be set to %s because it's not in a %s or %s status.", models.PPMShipmentStatusWaitingOnCustomer, models.PPMShipmentStatusSubmitted, - models.PPMShipmentStatusNeedsPaymentApproval, + models.PPMShipmentStatusNeedsCloseout, ), ) } @@ -94,20 +94,20 @@ func (p *ppmShipmentRouter) SendToCustomer(appCtx appcontext.AppContext, ppmShip return nil } -// SubmitCloseOutDocumentation sets the PPM shipment to the NEEDS_PAYMENT_APPROVAL status +// SubmitCloseOutDocumentation sets the PPM shipment to the NEEDS_CLOSEOUT status func (p *ppmShipmentRouter) SubmitCloseOutDocumentation(_ appcontext.AppContext, ppmShipment *models.PPMShipment) error { if ppmShipment.Status != models.PPMShipmentStatusWaitingOnCustomer { return apperror.NewConflictError( ppmShipment.ID, fmt.Sprintf( "PPM shipment can't be set to %s because it's not in the %s status.", - models.PPMShipmentStatusNeedsPaymentApproval, + models.PPMShipmentStatusNeedsCloseout, models.PPMShipmentStatusWaitingOnCustomer, ), ) } - ppmShipment.Status = models.PPMShipmentStatusNeedsPaymentApproval + ppmShipment.Status = models.PPMShipmentStatusNeedsCloseout if ppmShipment.SubmittedAt == nil { ppmShipment.SubmittedAt = models.TimePointer(time.Now()) @@ -116,14 +116,14 @@ func (p *ppmShipmentRouter) SubmitCloseOutDocumentation(_ appcontext.AppContext, return nil } -// SubmitReviewedDocuments sets the PPM shipment status to the PAYMENT_APPROVED if all docs approved otherwise WAITING_ON_CUSTOMER +// SubmitReviewedDocuments sets the PPM shipment status to the CLOSEOUT_COMPLETE if all docs approved otherwise WAITING_ON_CUSTOMER func (p *ppmShipmentRouter) SubmitReviewedDocuments(_ appcontext.AppContext, ppmShipment *models.PPMShipment) error { - if ppmShipment.Status != models.PPMShipmentStatusNeedsPaymentApproval { + if ppmShipment.Status != models.PPMShipmentStatusNeedsCloseout { return apperror.NewConflictError( ppmShipment.ID, fmt.Sprintf( "PPM shipment documents cannot be submitted because it's not in the %s status.", - models.PPMShipmentStatusNeedsPaymentApproval, + models.PPMShipmentStatusNeedsCloseout, ), ) } @@ -159,7 +159,7 @@ func (p *ppmShipmentRouter) SubmitReviewedDocuments(_ appcontext.AppContext, ppm if hasRejectedDocuments { ppmShipment.Status = models.PPMShipmentStatusWaitingOnCustomer } else { - ppmShipment.Status = models.PPMShipmentStatusPaymentApproved + ppmShipment.Status = models.PPMShipmentStatusCloseoutComplete } return nil diff --git a/pkg/services/ppmshipment/ppm_shipment_router_test.go b/pkg/services/ppmshipment/ppm_shipment_router_test.go index a16cf80cd77..690a2e329df 100644 --- a/pkg/services/ppmshipment/ppm_shipment_router_test.go +++ b/pkg/services/ppmshipment/ppm_shipment_router_test.go @@ -153,8 +153,8 @@ func (suite *PPMShipmentSuite) TestSendToCustomer() { models.PPMShipmentStatusSubmitted: func() models.PPMShipment { return factory.BuildPPMShipment(nil, nil, nil) }, - models.PPMShipmentStatusNeedsPaymentApproval: func() models.PPMShipment { - return factory.BuildPPMShipmentThatNeedsPaymentApproval(nil, nil, nil) + models.PPMShipmentStatusNeedsCloseout: func() models.PPMShipment { + return factory.BuildPPMShipmentThatNeedsCloseout(nil, nil, nil) }, } @@ -226,7 +226,7 @@ func (suite *PPMShipmentSuite) TestSendToCustomer() { "PPM shipment can't be set to %s because it's not in a %s or %s status.", models.PPMShipmentStatusWaitingOnCustomer, models.PPMShipmentStatusSubmitted, - models.PPMShipmentStatusNeedsPaymentApproval, + models.PPMShipmentStatusNeedsCloseout, ), ) @@ -301,7 +301,7 @@ func (suite *PPMShipmentSuite) TestSendToCustomer() { func (suite *PPMShipmentSuite) TestSubmitCloseOutDocumentation() { mtoShipmentRouterMethodToMock := "" - suite.Run(fmt.Sprintf("Can set status to %s if it is currently %s", models.PPMShipmentStatusNeedsPaymentApproval, models.PPMShipmentStatusWaitingOnCustomer), func() { + suite.Run(fmt.Sprintf("Can set status to %s if it is currently %s", models.PPMShipmentStatusNeedsCloseout, models.PPMShipmentStatusWaitingOnCustomer), func() { ppmShipment := factory.BuildPPMShipmentReadyForFinalCustomerCloseOut(nil, nil, nil) ppmShipmentRouter := setUpPPMShipmentRouter(mtoShipmentRouterMethodToMock, nil) @@ -309,7 +309,7 @@ func (suite *PPMShipmentSuite) TestSubmitCloseOutDocumentation() { err := ppmShipmentRouter.SubmitCloseOutDocumentation(suite.AppContextForTest(), &ppmShipment) if suite.NoError(err) { - suite.Equal(models.PPMShipmentStatusNeedsPaymentApproval, ppmShipment.Status) + suite.Equal(models.PPMShipmentStatusNeedsCloseout, ppmShipment.Status) suite.NotNil(ppmShipment.SubmittedAt) } @@ -334,7 +334,7 @@ func (suite *PPMShipmentSuite) TestSubmitCloseOutDocumentation() { err := ppmShipmentRouter.SubmitCloseOutDocumentation(suite.AppContextForTest(), &ppmShipment) if suite.NoError(err) { - suite.Equal(models.PPMShipmentStatusNeedsPaymentApproval, ppmShipment.Status) + suite.Equal(models.PPMShipmentStatusNeedsCloseout, ppmShipment.Status) suite.True(originalSubmittedAt.Equal(*ppmShipment.SubmittedAt), "SubmittedAt should not have changed") } @@ -353,8 +353,8 @@ func (suite *PPMShipmentSuite) TestSubmitCloseOutDocumentation() { models.PPMShipmentStatusSubmitted: func() models.PPMShipment { return factory.BuildPPMShipment(nil, nil, nil) }, - models.PPMShipmentStatusNeedsPaymentApproval: func() models.PPMShipment { - return factory.BuildPPMShipmentThatNeedsPaymentApproval(nil, nil, nil) + models.PPMShipmentStatusNeedsCloseout: func() models.PPMShipment { + return factory.BuildPPMShipmentThatNeedsCloseout(nil, nil, nil) }, } @@ -362,7 +362,7 @@ func (suite *PPMShipmentSuite) TestSubmitCloseOutDocumentation() { currentStatus := currentStatus makePPMShipment := makePPMShipment - suite.Run(fmt.Sprintf("Can't set status to %s if it is currently %s", models.PPMShipmentStatusNeedsPaymentApproval, currentStatus), func() { + suite.Run(fmt.Sprintf("Can't set status to %s if it is currently %s", models.PPMShipmentStatusNeedsCloseout, currentStatus), func() { ppmShipment := makePPMShipment() ppmShipmentRouter := setUpPPMShipmentRouter(mtoShipmentRouterMethodToMock, nil) @@ -375,7 +375,7 @@ func (suite *PPMShipmentSuite) TestSubmitCloseOutDocumentation() { err.Error(), fmt.Sprintf( "PPM shipment can't be set to %s because it's not in the %s status.", - models.PPMShipmentStatusNeedsPaymentApproval, + models.PPMShipmentStatusNeedsCloseout, models.PPMShipmentStatusWaitingOnCustomer, ), ) @@ -399,7 +399,7 @@ func (suite *PPMShipmentSuite) TestSubmitReviewPPMDocuments() { }, }, }, nil) - ppmShipment.Status = models.PPMShipmentStatusNeedsPaymentApproval + ppmShipment.Status = models.PPMShipmentStatusNeedsCloseout movingExpense := factory.BuildMovingExpense(suite.DB(), nil, nil) progear := factory.BuildProgearWeightTicket(suite.DB(), nil, nil) @@ -416,7 +416,7 @@ func (suite *PPMShipmentSuite) TestSubmitReviewPPMDocuments() { suite.Run("Update PPMShipment Status to WAITING_ON_CUSTOMER when there are rejected progear weight tickets", func() { ppmShipment := factory.BuildPPMShipmentReadyForFinalCustomerCloseOut(nil, nil, nil) - ppmShipment.Status = models.PPMShipmentStatusNeedsPaymentApproval + ppmShipment.Status = models.PPMShipmentStatusNeedsCloseout rejected := models.PPMDocumentStatusRejected progear := factory.BuildProgearWeightTicket(suite.DB(), []factory.Customization{ { @@ -441,7 +441,7 @@ func (suite *PPMShipmentSuite) TestSubmitReviewPPMDocuments() { suite.Run("Update PPMShipment Status to WAITING_ON_CUSTOMER when there are rejected moving expenses", func() { ppmShipment := factory.BuildPPMShipmentReadyForFinalCustomerCloseOut(nil, nil, nil) - ppmShipment.Status = models.PPMShipmentStatusNeedsPaymentApproval + ppmShipment.Status = models.PPMShipmentStatusNeedsCloseout rejected := models.PPMDocumentStatusRejected movingExpense := factory.BuildMovingExpense(suite.DB(), []factory.Customization{ { @@ -464,9 +464,9 @@ func (suite *PPMShipmentSuite) TestSubmitReviewPPMDocuments() { } }) - suite.Run("Update PPMShipment Status to PAYMENT_APPROVED when there are no rejected PPM Documents", func() { + suite.Run("Update PPMShipment Status to CLOSEOUT_COMPLETE when there are no rejected PPM Documents", func() { ppmShipment := factory.BuildPPMShipmentReadyForFinalCustomerCloseOut(nil, nil, nil) - ppmShipment.Status = models.PPMShipmentStatusNeedsPaymentApproval + ppmShipment.Status = models.PPMShipmentStatusNeedsCloseout movingExpense := factory.BuildMovingExpense(suite.DB(), nil, nil) progear := factory.BuildProgearWeightTicket(suite.DB(), nil, nil) weightTicket := factory.BuildWeightTicket(suite.DB(), nil, nil) @@ -478,7 +478,7 @@ func (suite *PPMShipmentSuite) TestSubmitReviewPPMDocuments() { err := ppmShipmentRouter.SubmitReviewedDocuments(suite.AppContextForTest(), &ppmShipment) if suite.NoError(err) { - suite.Equal(models.PPMShipmentStatusPaymentApproved, ppmShipment.Status) + suite.Equal(models.PPMShipmentStatusCloseoutComplete, ppmShipment.Status) } }) @@ -498,11 +498,11 @@ func (suite *PPMShipmentSuite) TestSubmitReviewPPMDocuments() { models.PPMShipmentStatusWaitingOnCustomer: func() models.PPMShipment { return factory.BuildPPMShipment(nil, nil, []factory.Trait{factory.GetTraitApprovedPPMWithActualInfo}) }, - models.PPMShipmentStatusPaymentApproved: func() models.PPMShipment { + models.PPMShipmentStatusCloseoutComplete: func() models.PPMShipment { return factory.BuildPPMShipment(nil, []factory.Customization{ { Model: models.PPMShipment{ - Status: models.PPMShipmentStatusPaymentApproved, + Status: models.PPMShipmentStatusCloseoutComplete, }, }, }, []factory.Trait{factory.GetTraitApprovedPPMWithActualInfo}) @@ -522,7 +522,7 @@ func (suite *PPMShipmentSuite) TestSubmitReviewPPMDocuments() { currentStatus := currentStatus makePPMShipment := makePPMShipment - suite.Run(fmt.Sprintf("Can't set status to %s if it is currently %s", models.PPMShipmentStatusNeedsPaymentApproval, currentStatus), func() { + suite.Run(fmt.Sprintf("Can't set status to %s if it is currently %s", models.PPMShipmentStatusNeedsCloseout, currentStatus), func() { ppmShipment := makePPMShipment() ppmShipmentRouter := setUpPPMShipmentRouter(mtoShipmentRouterMethodToMock, nil) @@ -535,7 +535,7 @@ func (suite *PPMShipmentSuite) TestSubmitReviewPPMDocuments() { err.Error(), fmt.Sprintf( "PPM shipment documents cannot be submitted because it's not in the %s status.", - models.PPMShipmentStatusNeedsPaymentApproval, + models.PPMShipmentStatusNeedsCloseout, ), ) diff --git a/pkg/services/ppmshipment/ppm_shipment_updated_submitter_test.go b/pkg/services/ppmshipment/ppm_shipment_updated_submitter_test.go index a0580527625..888b1dfba03 100644 --- a/pkg/services/ppmshipment/ppm_shipment_updated_submitter_test.go +++ b/pkg/services/ppmshipment/ppm_shipment_updated_submitter_test.go @@ -90,7 +90,7 @@ func (suite *PPMShipmentSuite) TestSubmitCustomerCloseOut() { }) suite.Run("Returns an error if updating an existing signed certification fails", func() { - existingPPMShipment := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), nil, nil) + existingPPMShipment := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), nil, nil) appCtx := suite.AppContextWithSessionForTest(&auth.Session{ UserID: existingPPMShipment.Shipment.MoveTaskOrder.Orders.ServiceMember.User.ID, @@ -153,7 +153,7 @@ func (suite *PPMShipmentSuite) TestSubmitCustomerCloseOut() { }) suite.Run("Can update a signed certification and route the PPMShipment properly", func() { - existingPPMShipment := factory.BuildPPMShipmentThatNeedsPaymentApproval(suite.DB(), nil, nil) + existingPPMShipment := factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), nil, nil) userID := existingPPMShipment.Shipment.MoveTaskOrder.Orders.ServiceMember.User.ID appCtx := suite.AppContextWithSessionForTest(&auth.Session{ @@ -191,7 +191,7 @@ func (suite *PPMShipmentSuite) TestSubmitCustomerCloseOut() { mockRouter := setUpPPMShipperRouterMock( func(_ appcontext.AppContext, ppmShipment *models.PPMShipment) error { - ppmShipment.Status = models.PPMShipmentStatusNeedsPaymentApproval + ppmShipment.Status = models.PPMShipmentStatusNeedsCloseout return nil }) @@ -213,7 +213,7 @@ func (suite *PPMShipmentSuite) TestSubmitCustomerCloseOut() { ) if suite.NoError(err) && suite.NotNil(updatedPPMShipment) { - suite.Equal(models.PPMShipmentStatusNeedsPaymentApproval, updatedPPMShipment.Status) + suite.Equal(models.PPMShipmentStatusNeedsCloseout, updatedPPMShipment.Status) if suite.NotNil(updatedPPMShipment.SignedCertification) { suite.Equal(updatedSignedCertification.ID, updatedPPMShipment.SignedCertification.ID) diff --git a/pkg/services/progear_weight_ticket/progear_weight_ticket_updater.go b/pkg/services/progear_weight_ticket/progear_weight_ticket_updater.go index 19c9a023194..8041be410fd 100644 --- a/pkg/services/progear_weight_ticket/progear_weight_ticket_updater.go +++ b/pkg/services/progear_weight_ticket/progear_weight_ticket_updater.go @@ -51,6 +51,18 @@ func (f *progearWeightTicketUpdater) UpdateProgearWeightTicket(appCtx appcontext return nil, err } + if appCtx.Session().IsMilApp() { + if mergedProgearWeightTicket.Weight != nil { + mergedProgearWeightTicket.SubmittedWeight = mergedProgearWeightTicket.Weight + } + if mergedProgearWeightTicket.BelongsToSelf != nil { + mergedProgearWeightTicket.SubmittedBelongsToSelf = mergedProgearWeightTicket.BelongsToSelf + } + if mergedProgearWeightTicket.HasWeightTickets != nil { + mergedProgearWeightTicket.SubmittedHasWeightTickets = mergedProgearWeightTicket.HasWeightTickets + } + } + // update the DB record txnErr := appCtx.NewTransaction(func(txnCtx appcontext.AppContext) error { verrs, err := txnCtx.DB().ValidateAndUpdate(&mergedProgearWeightTicket) diff --git a/pkg/services/progear_weight_ticket/progear_weight_ticket_updater_test.go b/pkg/services/progear_weight_ticket/progear_weight_ticket_updater_test.go index a6a4476a282..bc59f7c1366 100644 --- a/pkg/services/progear_weight_ticket/progear_weight_ticket_updater_test.go +++ b/pkg/services/progear_weight_ticket/progear_weight_ticket_updater_test.go @@ -147,6 +147,9 @@ func (suite *ProgearWeightTicketSuite) TestUpdateProgearWeightTicket() { suite.Equal(*desiredProgearWeightTicket.Weight, *updatedProgearWeightTicket.Weight) suite.Equal(*desiredProgearWeightTicket.HasWeightTickets, *updatedProgearWeightTicket.HasWeightTickets) suite.Equal(*desiredProgearWeightTicket.BelongsToSelf, *updatedProgearWeightTicket.BelongsToSelf) + suite.Equal(*desiredProgearWeightTicket.Weight, *updatedProgearWeightTicket.SubmittedWeight) + suite.Equal(*desiredProgearWeightTicket.BelongsToSelf, *updatedProgearWeightTicket.SubmittedBelongsToSelf) + suite.Equal(*desiredProgearWeightTicket.HasWeightTickets, *updatedProgearWeightTicket.SubmittedHasWeightTickets) }) suite.Run("Succesfully updates when files are required", func() { @@ -175,6 +178,9 @@ func (suite *ProgearWeightTicketSuite) TestUpdateProgearWeightTicket() { suite.Equal(*desiredProgearWeightTicket.Weight, *updatedProgearWeightTicket.Weight) suite.Equal(*desiredProgearWeightTicket.HasWeightTickets, *updatedProgearWeightTicket.HasWeightTickets) suite.Equal(*desiredProgearWeightTicket.BelongsToSelf, *updatedProgearWeightTicket.BelongsToSelf) + suite.Equal(*desiredProgearWeightTicket.Weight, *updatedProgearWeightTicket.SubmittedWeight) + suite.Equal(*desiredProgearWeightTicket.BelongsToSelf, *updatedProgearWeightTicket.SubmittedBelongsToSelf) + suite.Equal(*desiredProgearWeightTicket.HasWeightTickets, *updatedProgearWeightTicket.SubmittedHasWeightTickets) suite.Len(updatedProgearWeightTicket.Document.UserUploads, 2) }) diff --git a/pkg/services/query/query_builder_test.go b/pkg/services/query/query_builder_test.go index 1755b9cdee1..794e4cf60b2 100644 --- a/pkg/services/query/query_builder_test.go +++ b/pkg/services/query/query_builder_test.go @@ -441,7 +441,7 @@ func (suite *QueryBuilderSuite) TestCount() { suite.Run("counts with time filter", func() { user := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeTOO}) - factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeQaeCsr}) + factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeQae}) filters := []services.QueryFilter{ NewQueryFilter("created_at", greaterThan, user.CreatedAt), } diff --git a/pkg/services/shipment_address_update/shipment_address_update_requester.go b/pkg/services/shipment_address_update/shipment_address_update_requester.go index 1df50b2b781..e226a61ddd6 100644 --- a/pkg/services/shipment_address_update/shipment_address_update_requester.go +++ b/pkg/services/shipment_address_update/shipment_address_update_requester.go @@ -13,6 +13,7 @@ import ( serviceparamvaluelookups "github.com/transcom/mymove/pkg/payment_request/service_param_value_lookups" "github.com/transcom/mymove/pkg/route" "github.com/transcom/mymove/pkg/services" + "github.com/transcom/mymove/pkg/services/ghcrateengine" mtoserviceitem "github.com/transcom/mymove/pkg/services/mto_service_item" mtoshipment "github.com/transcom/mymove/pkg/services/mto_shipment" "github.com/transcom/mymove/pkg/services/query" @@ -448,7 +449,7 @@ func (f *shipmentAddressUpdateRequester) ReviewShipmentAddressChange(appCtx appc if tooApprovalStatus == models.ShipmentAddressUpdateStatusApproved { queryBuilder := query.NewQueryBuilder() serviceItemUpdater := mtoserviceitem.NewMTOServiceItemUpdater(f.planner, queryBuilder, f.moveRouter, f.shipmentFetcher, f.addressCreator) - serviceItemCreator := mtoserviceitem.NewMTOServiceItemCreator(f.planner, queryBuilder, f.moveRouter) + serviceItemCreator := mtoserviceitem.NewMTOServiceItemCreator(f.planner, queryBuilder, f.moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) addressUpdate.Status = models.ShipmentAddressUpdateStatusApproved addressUpdate.OfficeRemarks = &tooRemarks diff --git a/pkg/services/shipment_summary_worksheet.go b/pkg/services/shipment_summary_worksheet.go index c0785f009b3..55418e5cb46 100644 --- a/pkg/services/shipment_summary_worksheet.go +++ b/pkg/services/shipment_summary_worksheet.go @@ -93,9 +93,6 @@ type Page2Values struct { TotalPaidSIT string ShipmentPickupDates string TrustedAgentName string - TrustedAgentDate string - TrustedAgentEmail string - TrustedAgentPhone string FormattedMovingExpenses ServiceMemberSignature string SignatureDate string @@ -150,7 +147,6 @@ type ShipmentSummaryFormData struct { PreparationDate time.Time Obligations Obligations MovingExpenses models.MovingExpenses - MTOAgents models.MTOAgents PPMRemainingEntitlement unit.Pound SignedCertification models.SignedCertification MaxSITStorageEntitlement int diff --git a/pkg/services/shipment_summary_worksheet/shipment_summary_worksheet.go b/pkg/services/shipment_summary_worksheet/shipment_summary_worksheet.go index 2910d1c5d3e..2102e774b31 100644 --- a/pkg/services/shipment_summary_worksheet/shipment_summary_worksheet.go +++ b/pkg/services/shipment_summary_worksheet/shipment_summary_worksheet.go @@ -144,13 +144,6 @@ type SSWMaxWeightEntitlement struct { TotalWeight unit.Pound } -type Agent struct { - Name string - Email string - Date string - Phone string -} - // adds a line item to shipment summary worksheet SSWMaxWeightEntitlement and increments total allotment func (wa *SSWMaxWeightEntitlement) addLineItem(field string, value int) { r := reflect.ValueOf(wa).Elem() @@ -198,6 +191,10 @@ const ( controlledUnclassifiedInformationText = "CONTROLLED UNCLASSIFIED INFORMATION" ) +const ( + trustedAgentText = "Trusted Agent Requires POA \nor Letter of Authorization" +) + // FormatValuesShipmentSummaryWorksheetFormPage1 formats the data for page 1 of the Shipment Summary Worksheet func FormatValuesShipmentSummaryWorksheetFormPage1(data services.ShipmentSummaryFormData) services.Page1Values { page1 := services.Page1Values{} @@ -294,7 +291,6 @@ func FormatGrade(grade *internalmessages.OrderPayGrade) string { func FormatValuesShipmentSummaryWorksheetFormPage2(data services.ShipmentSummaryFormData) services.Page2Values { expensesMap := SubTotalExpenses(data.MovingExpenses) - agentInfo := FormatAgentInfo(data.MTOAgents) formattedShipments := FormatAllShipments(data.PPMShipments) page2 := services.Page2Values{} @@ -325,10 +321,7 @@ func FormatValuesShipmentSummaryWorksheetFormPage2(data services.ShipmentSummary page2.TotalMemberPaidRepeated = page2.TotalMemberPaid page2.TotalGTCCPaidRepeated = page2.TotalGTCCPaid page2.ShipmentPickupDates = formattedShipments.PickUpDates - page2.TrustedAgentName = agentInfo.Name - page2.TrustedAgentDate = agentInfo.Date - page2.TrustedAgentEmail = agentInfo.Email - page2.TrustedAgentPhone = agentInfo.Phone + page2.TrustedAgentName = trustedAgentText page2.ServiceMemberSignature = FormatSignature(data.ServiceMember) page2.SignatureDate = FormatSignatureDate(data.SignedCertification.UpdatedAt) return page2 @@ -344,36 +337,6 @@ func formatMaxAdvance(estimatedIncentive *unit.Cents) string { } -func FormatAgentInfo(agentArray []models.MTOAgent) Agent { - agentObject := Agent{} - if len(agentArray) == 0 { - agentObject.Name = "No agent specified" - agentObject.Email = "No agent specified" - agentObject.Date = "No agent specified" - agentObject.Phone = "No agent specified" - return agentObject - } - - agent := agentArray[0] - - switch { - case agent.FirstName != nil && agent.LastName != nil: - agentObject.Name = fmt.Sprintf("%s, %s", *agent.LastName, *agent.FirstName) - case agent.FirstName == nil && agent.LastName == nil: - agentObject.Name = "No name specified" - case agent.FirstName == nil: - agentObject.Name = fmt.Sprintf("No first name provided, Last Name: %s", *agent.LastName) - case agent.LastName == nil: - agentObject.Name = fmt.Sprintf("First Name: %s, No last name provided", *agent.FirstName) - } - - agentObject.Email = getOrDefault(agent.Email, "No Email Specified") - agentObject.Phone = getOrDefault(agent.Phone, "No Phone Specified") - agentObject.Date = agent.UpdatedAt.Format("20060102") - - return agentObject -} - func getOrDefault(value *string, defaultValue string) string { if value != nil { return *value @@ -534,6 +497,9 @@ func SubTotalExpenses(expenseDocuments models.MovingExpenses) map[string]float64 totals := make(map[string]float64) for _, expense := range expenseDocuments { + if expense.MovingExpenseType == nil || expense.Amount == nil { + continue + } // Added quick nil check to ensure SSW returns while weight tickets are being added still expenseType, addToTotal := getExpenseType(expense) expenseDollarAmt := expense.Amount.ToDollarFloatNoRound() @@ -708,7 +674,6 @@ func (SSWPPMComputer *SSWPPMComputer) FetchDataShipmentSummaryWorksheetFormData( "Shipment.MoveTaskOrder.Orders.ServiceMember", "Shipment.MoveTaskOrder.Orders.NewDutyLocation.Address", "Shipment.MoveTaskOrder.Orders.OriginDutyLocation.Address", - "Shipment.MTOAgents", "W2Address", "SignedCertification", "MovingExpenses", @@ -757,7 +722,6 @@ func (SSWPPMComputer *SSWPPMComputer) FetchDataShipmentSummaryWorksheetFormData( PPMShipments: ppmShipments, W2Address: ppmShipment.W2Address, MovingExpenses: ppmShipment.MovingExpenses, - MTOAgents: ppmShipment.Shipment.MTOAgents, SignedCertification: *signedCertification, PPMRemainingEntitlement: ppmRemainingEntitlement, MaxSITStorageEntitlement: maxSit, @@ -830,8 +794,8 @@ func (SSWPPMGenerator *SSWPPMGenerator) FillSSWPDFForm(Page1Values services.Page var sswHeader = header{ Source: "SSWPDFTemplate.pdf", - Version: "pdfcpu v0.6.0 dev", - Creation: "2024-03-08 17:36:47 UTC", + Version: "pdfcpu v0.8.0 dev", + Creation: "2024-06-04 17:34:35 UTC", Producer: "macOS Version 13.5 (Build 22G74) Quartz PDFContext, AppendMode 1.1", } 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 f8adf073ea2..a9fbf471819 100644 --- a/pkg/services/shipment_summary_worksheet/shipment_summary_worksheet_test.go +++ b/pkg/services/shipment_summary_worksheet/shipment_summary_worksheet_test.go @@ -875,105 +875,3 @@ func (suite *ShipmentSummaryWorksheetServiceSuite) TestFormatCurrentShipment() { } } - -type mockMTOAgent struct { - FirstName *string - LastName *string - Email *string - Phone *string - UpdatedAt time.Time -} - -func (suite *ShipmentSummaryWorksheetServiceSuite) TestFormatAgentInfo() { - exampleFirstName := "John" - exampleLastName := "Doe" - exampleEmail := "john.doe@example.com" - examplePhone := "123-456-7890" - tests := []struct { - name string - agents []mockMTOAgent - expectedResult Agent - }{ - { - name: "No agents specified", - agents: []mockMTOAgent{}, - expectedResult: Agent{ - Name: "No agent specified", - Email: "No agent specified", - Phone: "No agent specified", - Date: "No agent specified", - }, - }, - { - name: "Agent with first and last name specified", - agents: []mockMTOAgent{ - { - FirstName: &exampleFirstName, - LastName: &exampleLastName, - Email: &exampleEmail, - Phone: &examplePhone, - UpdatedAt: time.Now(), - }, - }, - expectedResult: Agent{ - Name: "Doe, John", - Email: "john.doe@example.com", - Phone: "123-456-7890", - Date: time.Now().Format("20060102"), - }, - }, - { - name: "Agent with only first name specified", - agents: []mockMTOAgent{ - { - FirstName: &exampleFirstName, - Email: &exampleEmail, - Phone: &examplePhone, - UpdatedAt: time.Now(), - }, - }, - expectedResult: Agent{ - Name: "First Name: John, No last name provided", - Email: "john.doe@example.com", - Phone: "123-456-7890", - Date: time.Now().Format("20060102"), - }, - }, - { - name: "Agent with only last name specified", - agents: []mockMTOAgent{ - { - LastName: &exampleLastName, - Email: &exampleEmail, - Phone: &examplePhone, - UpdatedAt: time.Now(), - }, - }, - expectedResult: Agent{ - Name: "No first name provided, Last Name: Doe", - Email: "john.doe@example.com", - Phone: "123-456-7890", - Date: time.Now().Format("20060102"), - }, - }, - } - - for _, tt := range tests { - agents := make([]models.MTOAgent, len(tt.agents)) - for i, mockAgent := range tt.agents { - agents[i] = models.MTOAgent{ - FirstName: mockAgent.FirstName, - LastName: mockAgent.LastName, - Email: mockAgent.Email, - Phone: mockAgent.Phone, - UpdatedAt: mockAgent.UpdatedAt, - } - } - - result := FormatAgentInfo(agents) - suite.Equal(tt.expectedResult.Name, result.Name) - suite.Equal(tt.expectedResult.Email, result.Email) - suite.Equal(tt.expectedResult.Phone, result.Phone) - suite.Equal(tt.expectedResult.Date, result.Date) - } -} diff --git a/pkg/services/weight_ticket/weight_ticket_updater.go b/pkg/services/weight_ticket/weight_ticket_updater.go index 1231e806f6c..9a78d3288af 100644 --- a/pkg/services/weight_ticket/weight_ticket_updater.go +++ b/pkg/services/weight_ticket/weight_ticket_updater.go @@ -72,6 +72,21 @@ func (f *weightTicketUpdater) UpdateWeightTicket(appCtx appcontext.AppContext, w } } + if appCtx.Session().IsMilApp() { + if mergedWeightTicket.EmptyWeight != nil { + mergedWeightTicket.SubmittedEmptyWeight = mergedWeightTicket.EmptyWeight + } + if mergedWeightTicket.FullWeight != nil { + mergedWeightTicket.SubmittedFullWeight = mergedWeightTicket.FullWeight + } + if mergedWeightTicket.OwnsTrailer != nil { + mergedWeightTicket.SubmittedOwnsTrailer = mergedWeightTicket.OwnsTrailer + } + if mergedWeightTicket.TrailerMeetsCriteria != nil { + mergedWeightTicket.SubmittedTrailerMeetsCriteria = mergedWeightTicket.TrailerMeetsCriteria + } + } + // update the DB record txnErr := appCtx.NewTransaction(func(txnCtx appcontext.AppContext) error { // if weight changes call update PPMShipment with new weightTicket diff --git a/pkg/services/weight_ticket/weight_ticket_updater_test.go b/pkg/services/weight_ticket/weight_ticket_updater_test.go index f35dc8284fd..98394e6d7c8 100644 --- a/pkg/services/weight_ticket/weight_ticket_updater_test.go +++ b/pkg/services/weight_ticket/weight_ticket_updater_test.go @@ -212,6 +212,10 @@ func (suite *WeightTicketSuite) TestUpdateWeightTicket() { suite.Equal(*desiredWeightTicket.TrailerMeetsCriteria, *updatedWeightTicket.TrailerMeetsCriteria) suite.Equal(*desiredWeightTicket.AdjustedNetWeight, *updatedWeightTicket.AdjustedNetWeight) suite.Equal(*desiredWeightTicket.NetWeightRemarks, *updatedWeightTicket.NetWeightRemarks) + suite.Equal(*desiredWeightTicket.EmptyWeight, *updatedWeightTicket.SubmittedEmptyWeight) + suite.Equal(*desiredWeightTicket.FullWeight, *updatedWeightTicket.SubmittedFullWeight) + suite.Equal(*desiredWeightTicket.OwnsTrailer, *updatedWeightTicket.SubmittedOwnsTrailer) + suite.Equal(*desiredWeightTicket.TrailerMeetsCriteria, *updatedWeightTicket.SubmittedTrailerMeetsCriteria) }) suite.Run("Succesfully updates when files are required", func() { @@ -257,6 +261,10 @@ func (suite *WeightTicketSuite) TestUpdateWeightTicket() { suite.Equal(*desiredWeightTicket.TrailerMeetsCriteria, *updatedWeightTicket.TrailerMeetsCriteria) suite.Equal(*desiredWeightTicket.AdjustedNetWeight, *updatedWeightTicket.AdjustedNetWeight) suite.Equal(*desiredWeightTicket.NetWeightRemarks, *updatedWeightTicket.NetWeightRemarks) + suite.Equal(*desiredWeightTicket.EmptyWeight, *updatedWeightTicket.SubmittedEmptyWeight) + suite.Equal(*desiredWeightTicket.FullWeight, *updatedWeightTicket.SubmittedFullWeight) + suite.Equal(*desiredWeightTicket.OwnsTrailer, *updatedWeightTicket.SubmittedOwnsTrailer) + suite.Equal(*desiredWeightTicket.TrailerMeetsCriteria, *updatedWeightTicket.SubmittedTrailerMeetsCriteria) suite.Equal(1, len(updatedWeightTicket.EmptyDocument.UserUploads)) suite.Equal(2, len(updatedWeightTicket.FullDocument.UserUploads)) suite.Equal(2, len(updatedWeightTicket.ProofOfTrailerOwnershipDocument.UserUploads)) @@ -309,6 +317,10 @@ func (suite *WeightTicketSuite) TestUpdateWeightTicket() { suite.Equal(*desiredWeightTicket.TrailerMeetsCriteria, *updatedWeightTicket.TrailerMeetsCriteria) suite.Equal(*desiredWeightTicket.AdjustedNetWeight, *updatedWeightTicket.AdjustedNetWeight) suite.Equal(*desiredWeightTicket.NetWeightRemarks, *updatedWeightTicket.NetWeightRemarks) + suite.Equal(*desiredWeightTicket.EmptyWeight, *updatedWeightTicket.SubmittedEmptyWeight) + suite.Equal(*desiredWeightTicket.FullWeight, *updatedWeightTicket.SubmittedFullWeight) + suite.Equal(*desiredWeightTicket.OwnsTrailer, *updatedWeightTicket.SubmittedOwnsTrailer) + suite.Equal(*desiredWeightTicket.TrailerMeetsCriteria, *updatedWeightTicket.SubmittedTrailerMeetsCriteria) }) suite.Run("Successfully updates and does not call ppmShipmentUpdater when total weight is unchanged", func() { @@ -354,6 +366,10 @@ func (suite *WeightTicketSuite) TestUpdateWeightTicket() { suite.Equal(*desiredWeightTicket.TrailerMeetsCriteria, *updatedWeightTicket.TrailerMeetsCriteria) suite.Equal(*desiredWeightTicket.AdjustedNetWeight, *updatedWeightTicket.AdjustedNetWeight) suite.Equal(*desiredWeightTicket.NetWeightRemarks, *updatedWeightTicket.NetWeightRemarks) + suite.Equal(*desiredWeightTicket.EmptyWeight, *updatedWeightTicket.SubmittedEmptyWeight) + suite.Equal(*desiredWeightTicket.FullWeight, *updatedWeightTicket.SubmittedFullWeight) + suite.Equal(*desiredWeightTicket.OwnsTrailer, *updatedWeightTicket.SubmittedOwnsTrailer) + suite.Equal(*desiredWeightTicket.TrailerMeetsCriteria, *updatedWeightTicket.SubmittedTrailerMeetsCriteria) }) suite.Run("Successfully updates when total weight is changed - taking adjustedNetWeight into account", func() { @@ -401,6 +417,10 @@ func (suite *WeightTicketSuite) TestUpdateWeightTicket() { suite.Equal(*desiredWeightTicket.TrailerMeetsCriteria, *updatedWeightTicket.TrailerMeetsCriteria) suite.Equal(*desiredWeightTicket.AdjustedNetWeight, *updatedWeightTicket.AdjustedNetWeight) suite.Equal(*desiredWeightTicket.NetWeightRemarks, *updatedWeightTicket.NetWeightRemarks) + suite.Equal(*desiredWeightTicket.EmptyWeight, *updatedWeightTicket.SubmittedEmptyWeight) + suite.Equal(*desiredWeightTicket.FullWeight, *updatedWeightTicket.SubmittedFullWeight) + suite.Equal(*desiredWeightTicket.OwnsTrailer, *updatedWeightTicket.SubmittedOwnsTrailer) + suite.Equal(*desiredWeightTicket.TrailerMeetsCriteria, *updatedWeightTicket.SubmittedTrailerMeetsCriteria) }) suite.Run("Fails to update when files are missing", func() { diff --git a/pkg/testdatagen/scenario/e2ebasic.go b/pkg/testdatagen/scenario/e2ebasic.go index 679105fa267..95e2cf91eb5 100644 --- a/pkg/testdatagen/scenario/e2ebasic.go +++ b/pkg/testdatagen/scenario/e2ebasic.go @@ -236,11 +236,11 @@ func userWithServicesCounselorRole(appCtx appcontext.AppContext) { }, nil) } -func userWithQAECSRRole(appCtx appcontext.AppContext, userID uuid.UUID, email string) { - qaecsrRole := roles.Role{} - err := appCtx.DB().Where("role_type = $1", roles.RoleTypeQaeCsr).First(&qaecsrRole) +func userWithQAERole(appCtx appcontext.AppContext, userID uuid.UUID, email string) { + qaeRole := roles.Role{} + err := appCtx.DB().Where("role_type = $1", roles.RoleTypeQae).First(&qaeRole) if err != nil { - log.Panic(fmt.Errorf("failed to find RoleTypeQAECSR in the DB: %w", err)) + log.Panic(fmt.Errorf("failed to find RoleTypeQAE in the DB: %w", err)) } oktaID := uuid.Must(uuid.NewV4()) @@ -252,7 +252,7 @@ func userWithQAECSRRole(appCtx appcontext.AppContext, userID uuid.UUID, email st OktaID: oktaID.String(), OktaEmail: email, Active: true, - Roles: []roles.Role{qaecsrRole}, + Roles: []roles.Role{qaeRole}, }, }, }, nil) @@ -320,7 +320,7 @@ func userWithTOOandTIORole(appCtx appcontext.AppContext) { }, nil) } -func userWithTOOandTIOandQAECSRRole(appCtx appcontext.AppContext) { +func userWithTOOandTIOandQAERole(appCtx appcontext.AppContext) { tooRole := roles.Role{} err := appCtx.DB().Where("role_type = $1", roles.RoleTypeTOO).First(&tooRole) if err != nil { @@ -333,24 +333,24 @@ func userWithTOOandTIOandQAECSRRole(appCtx appcontext.AppContext) { log.Panic(fmt.Errorf("Failed to find RoleTypeTIO in the DB: %w", err)) } - qaecsrRole := roles.Role{} - err = appCtx.DB().Where("role_type = $1", roles.RoleTypeQaeCsr).First(&qaecsrRole) + qaeRole := roles.Role{} + err = appCtx.DB().Where("role_type = $1", roles.RoleTypeQae).First(&qaeRole) if err != nil { - log.Panic(fmt.Errorf("failed to find RoleTypeQAECSR in the DB: %w", err)) + log.Panic(fmt.Errorf("failed to find RoleTypeQAE in the DB: %w", err)) } - email := "too_tio_qaecsr_role@office.mil" - tooTioQaecsrUUID := uuid.Must(uuid.FromString("b264abd6-52fc-4e42-9e0f-173f7d217bc5")) + email := "too_tio_qae_role@office.mil" + tooTioQaeUUID := uuid.Must(uuid.FromString("b264abd6-52fc-4e42-9e0f-173f7d217bc5")) oktaID := uuid.Must(uuid.NewV4()) user := factory.BuildUser(appCtx.DB(), []factory.Customization{ { Model: models.User{ - ID: tooTioQaecsrUUID, + ID: tooTioQaeUUID, OktaID: oktaID.String(), OktaEmail: email, Active: true, - Roles: []roles.Role{tooRole, tioRole, qaecsrRole}, + Roles: []roles.Role{tooRole, tioRole, qaeRole}, }, }, }, nil) @@ -361,7 +361,7 @@ func userWithTOOandTIOandQAECSRRole(appCtx appcontext.AppContext) { ID: uuid.FromStringOrNil("45a6b7c2-2484-49af-bb7f-3ca8c179bcfb"), Email: email, Active: true, - UserID: &tooTioQaecsrUUID, + UserID: &tooTioQaeUUID, }, }, }, nil) @@ -4331,11 +4331,11 @@ func (e e2eBasicScenario) Run(appCtx appcontext.AppContext, userUploader *upload userWithRoles(appCtx) userWithTOORole(appCtx) userWithTIORole(appCtx) - userWithQAECSRRole(appCtx, uuid.Must(uuid.FromString("2419b1d6-097f-4dc4-8171-8f858967b4db")), "qaecsr_role@office.mil") - userWithQAECSRRole(appCtx, uuid.Must(uuid.FromString("7f45b6bc-1131-4c9a-85ef-24552979d28d")), "qaecsr_role2@office.mil") + userWithQAERole(appCtx, uuid.Must(uuid.FromString("2419b1d6-097f-4dc4-8171-8f858967b4db")), "qae_role@office.mil") + userWithQAERole(appCtx, uuid.Must(uuid.FromString("7f45b6bc-1131-4c9a-85ef-24552979d28d")), "qae_role2@office.mil") userWithServicesCounselorRole(appCtx) userWithTOOandTIORole(appCtx) - userWithTOOandTIOandQAECSRRole(appCtx) + userWithTOOandTIOandQAERole(appCtx) userWithTOOandTIOandServicesCounselorRole(appCtx) userWithPrimeSimulatorRole(appCtx) diff --git a/pkg/testdatagen/scenario/shared.go b/pkg/testdatagen/scenario/shared.go index c19818018f4..e89dff60053 100644 --- a/pkg/testdatagen/scenario/shared.go +++ b/pkg/testdatagen/scenario/shared.go @@ -1201,7 +1201,7 @@ func createApprovedMoveWithPPMExcessWeight(appCtx appcontext.AppContext, userUpl PPMShipment: models.PPMShipment{ ID: uuid.Must(uuid.NewV4()), ApprovedAt: &approvedAt, - Status: models.PPMShipmentStatusNeedsPaymentApproval, + Status: models.PPMShipmentStatusNeedsCloseout, ActualMoveDate: models.TimePointer(time.Date(testdatagen.GHCTestYear, time.March, 16, 0, 0, 0, 0, time.UTC)), ActualPickupPostalCode: models.StringPointer("42444"), ActualDestinationPostalCode: models.StringPointer("30813"), @@ -1385,7 +1385,7 @@ func createApprovedMoveWithPPMCloseoutComplete(appCtx appcontext.AppContext, use ID: testdatagen.ConvertUUIDStringToUUID("defb263e-bf01-4c67-85f5-b64ab54fd4fe"), ApprovedAt: &approvedAt, SubmittedAt: models.TimePointer(approvedAt.Add(7 * time.Hour * 24)), - Status: models.PPMShipmentStatusNeedsPaymentApproval, + Status: models.PPMShipmentStatusNeedsCloseout, ActualMoveDate: models.TimePointer(time.Date(testdatagen.GHCTestYear, time.March, 16, 0, 0, 0, 0, time.UTC)), ActualPickupPostalCode: models.StringPointer("42444"), ActualDestinationPostalCode: models.StringPointer("30813"), @@ -1445,7 +1445,7 @@ func createApprovedMoveWithPPMCloseoutCompleteMultipleWeightTickets(appCtx appco ID: testdatagen.ConvertUUIDStringToUUID("08ab7a25-ef97-4134-bbb5-5be0e0de4734"), ApprovedAt: &approvedAt, SubmittedAt: models.TimePointer(approvedAt.Add(7 * time.Hour * 24)), - Status: models.PPMShipmentStatusNeedsPaymentApproval, + Status: models.PPMShipmentStatusNeedsCloseout, ActualMoveDate: models.TimePointer(time.Date(testdatagen.GHCTestYear, time.March, 16, 0, 0, 0, 0, time.UTC)), ActualPickupPostalCode: models.StringPointer("42444"), ActualDestinationPostalCode: models.StringPointer("30813"), @@ -1523,7 +1523,7 @@ func createApprovedMoveWithPPMCloseoutCompleteWithExpenses(appCtx appcontext.App ID: testdatagen.ConvertUUIDStringToUUID("645f9cd3-1aa2-4912-89fe-d0aa327226f6"), ApprovedAt: &approvedAt, SubmittedAt: models.TimePointer(approvedAt.Add(7 * time.Hour * 24)), - Status: models.PPMShipmentStatusNeedsPaymentApproval, + Status: models.PPMShipmentStatusNeedsCloseout, ActualMoveDate: models.TimePointer(time.Date(testdatagen.GHCTestYear, time.March, 16, 0, 0, 0, 0, time.UTC)), ActualPickupPostalCode: models.StringPointer("42444"), ActualDestinationPostalCode: models.StringPointer("30813"), @@ -1611,7 +1611,7 @@ func createApprovedMoveWithPPMCloseoutCompleteWithAllDocTypes(appCtx appcontext. ID: testdatagen.ConvertUUIDStringToUUID("1a719536-02ba-44cd-b97d-5a0548237dc5"), ApprovedAt: &approvedAt, SubmittedAt: models.TimePointer(approvedAt.Add(7 * time.Hour * 24)), - Status: models.PPMShipmentStatusNeedsPaymentApproval, + Status: models.PPMShipmentStatusNeedsCloseout, ActualMoveDate: models.TimePointer(time.Date(testdatagen.GHCTestYear, time.March, 16, 0, 0, 0, 0, time.UTC)), ActualPickupPostalCode: models.StringPointer("42444"), ActualDestinationPostalCode: models.StringPointer("30813"), @@ -2664,7 +2664,7 @@ func CreateMoveWithCloseOut(appCtx appcontext.AppContext, userUploader *uploader }, { Model: models.PPMShipment{ - Status: models.PPMShipmentStatusNeedsPaymentApproval, + Status: models.PPMShipmentStatusNeedsCloseout, SubmittedAt: models.TimePointer(time.Now()), }, }, @@ -2773,7 +2773,7 @@ func createMoveWithCloseOutandNonCloseOut(appCtx appcontext.AppContext, userUplo }, { Model: models.PPMShipment{ - Status: models.PPMShipmentStatusNeedsPaymentApproval, + Status: models.PPMShipmentStatusNeedsCloseout, }, }, }, nil) @@ -2897,7 +2897,7 @@ func createMoveWith2CloseOuts(appCtx appcontext.AppContext, userUploader *upload }, { Model: models.PPMShipment{ - Status: models.PPMShipmentStatusNeedsPaymentApproval, + Status: models.PPMShipmentStatusNeedsCloseout, }, }, }, nil) @@ -2913,7 +2913,7 @@ func createMoveWith2CloseOuts(appCtx appcontext.AppContext, userUploader *upload }, { Model: models.PPMShipment{ - Status: models.PPMShipmentStatusNeedsPaymentApproval, + Status: models.PPMShipmentStatusNeedsCloseout, }, }, }, nil) @@ -3021,7 +3021,7 @@ func createMoveWithCloseOutandHHG(appCtx appcontext.AppContext, userUploader *up }, { Model: models.PPMShipment{ - Status: models.PPMShipmentStatusNeedsPaymentApproval, + Status: models.PPMShipmentStatusNeedsCloseout, }, }, }, nil) @@ -3123,7 +3123,7 @@ func CreateMoveWithCloseoutOffice(appCtx appcontext.AppContext, moveInfo MoveCre }, { Model: models.PPMShipment{ - Status: models.PPMShipmentStatusNeedsPaymentApproval, + Status: models.PPMShipmentStatusNeedsCloseout, }, }, }, nil) @@ -4205,7 +4205,7 @@ func createHHGWithOriginSITServiceItems( ).Return(400, nil) queryBuilder := query.NewQueryBuilder() - serviceItemCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter) + serviceItemCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) mtoUpdater := movetaskorder.NewMoveTaskOrderUpdater(queryBuilder, serviceItemCreator, moveRouter) _, approveErr := mtoUpdater.MakeAvailableToPrime(appCtx, move.ID, etag.GenerateEtag(move.UpdatedAt), true, true) @@ -4467,7 +4467,7 @@ func createHHGWithDestinationSITServiceItems(appCtx appcontext.AppContext, prime mock.Anything, ).Return(400, nil) - serviceItemCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter) + serviceItemCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) mtoUpdater := movetaskorder.NewMoveTaskOrderUpdater(queryBuilder, serviceItemCreator, moveRouter) _, approveErr := mtoUpdater.MakeAvailableToPrime(appCtx, move.ID, etag.GenerateEtag(move.UpdatedAt), true, true) @@ -4870,7 +4870,7 @@ func createHHGWithPaymentServiceItems( planner := &routemocks.Planner{} planner.On("ZipTransitDistance", mock.AnythingOfType("*appcontext.appContext"), mock.Anything, mock.Anything).Return(123, nil).Once() - serviceItemCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter) + serviceItemCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) mtoUpdater := movetaskorder.NewMoveTaskOrderUpdater(queryBuilder, serviceItemCreator, moveRouter) _, approveErr := mtoUpdater.MakeAvailableToPrime(appCtx, move.ID, etag.GenerateEtag(move.UpdatedAt), true, true) @@ -4913,6 +4913,9 @@ func createHHGWithPaymentServiceItems( // called for domestic destination SIT delivery service item planner.On("ZipTransitDistance", mock.AnythingOfType("*appcontext.appContext"), "94535", "90210").Return(348, nil).Times(2) + // called for DLH, DSH, FSC service item estimated price calculations + planner.On("ZipTransitDistance", mock.AnythingOfType("*appcontext.appContext"), mock.Anything, mock.Anything).Return(400, nil).Times(3) + for _, shipment := range []models.MTOShipment{longhaulShipment, shorthaulShipment, shipmentWithOriginalWeight, shipmentWithOriginalAndReweighWeight, shipmentWithOriginalAndReweighWeightReweihBolded, shipmentWithOriginalReweighAndAdjustedWeight, shipmentWithOriginalAndAdjustedWeight} { shipmentUpdater := mtoshipment.NewMTOShipmentStatusUpdater(queryBuilder, serviceItemCreator, planner) _, updateErr := shipmentUpdater.UpdateMTOShipmentStatus(appCtx, shipment.ID, models.MTOShipmentStatusApproved, nil, nil, etag.GenerateEtag(shipment.UpdatedAt)) @@ -8580,9 +8583,9 @@ func createServicesCounselor(appCtx appcontext.AppContext) { }, nil) } -func createQaeCsr(appCtx appcontext.AppContext) { +func createQae(appCtx appcontext.AppContext) { db := appCtx.DB() - email := "qae_csr_role@office.mil" + email := "qae_role@office.mil" officeUser := models.OfficeUser{} officeUserExists, err := db.Where("email = $1", email).Exists(&officeUser) if err != nil { @@ -8594,22 +8597,22 @@ func createQaeCsr(appCtx appcontext.AppContext) { } /* A user with tio role */ - qaeCsrRole := roles.Role{} - err = db.Where("role_type = $1", roles.RoleTypeQaeCsr).First(&qaeCsrRole) + qaeRole := roles.Role{} + err = db.Where("role_type = $1", roles.RoleTypeQae).First(&qaeRole) if err != nil { - log.Panic(fmt.Errorf("Failed to find RoleTypeQaeCsr in the DB: %w", err)) + log.Panic(fmt.Errorf("Failed to find RoleTypeQae in the DB: %w", err)) } - qaeCsrUUID := uuid.Must(uuid.FromString("8dbf1648-7527-4a92-b4eb-524edb703982")) + qaeUUID := uuid.Must(uuid.FromString("8dbf1648-7527-4a92-b4eb-524edb703982")) oktaID := uuid.Must(uuid.NewV4()) factory.BuildUser(db, []factory.Customization{ { Model: models.User{ - ID: qaeCsrUUID, + ID: qaeUUID, OktaID: oktaID.String(), OktaEmail: email, Active: true, - Roles: []roles.Role{qaeCsrRole}, + Roles: []roles.Role{qaeRole}, }}, }, nil) factory.BuildOfficeUser(db, []factory.Customization{ @@ -8618,7 +8621,51 @@ func createQaeCsr(appCtx appcontext.AppContext) { ID: uuid.FromStringOrNil("ef4f6d1f-4ac3-4159-a364-5403e7d958ff"), Email: email, Active: true, - UserID: &qaeCsrUUID, + UserID: &qaeUUID, + }, + }, + }, nil) +} + +func createCustomerServiceRepresentative(appCtx appcontext.AppContext) { + db := appCtx.DB() + email := "customer_service_representative_role@office.mil" + officeUser := models.OfficeUser{} + officeUserExists, err := db.Where("email = $1", email).Exists(&officeUser) + if err != nil { + log.Panic(fmt.Errorf("Failed to query OfficeUser in the DB: %w", err)) + } + // no need to create + if officeUserExists { + return + } + + /* A user with RoleTypeCustomerServiceRepresentative role */ + customerServiceRepresentativeRole := roles.Role{} + err = db.Where("role_type = $1", roles.RoleTypeCustomerServiceRepresentative).First(&customerServiceRepresentativeRole) + if err != nil { + log.Panic(fmt.Errorf("Failed to find RoleTypeCustomerServiceRepresentative in the DB: %w", err)) + } + + csrUUID := uuid.Must(uuid.FromString("72432922-BF2E-45DE-8837-1A458F5D1011")) + oktaID := uuid.Must(uuid.NewV4()) + factory.BuildUser(db, []factory.Customization{ + { + Model: models.User{ + ID: csrUUID, + OktaID: oktaID.String(), + OktaEmail: email, + Active: true, + Roles: []roles.Role{customerServiceRepresentativeRole}, + }}, + }, nil) + factory.BuildOfficeUser(db, []factory.Customization{ + { + Model: models.OfficeUser{ + ID: uuid.FromStringOrNil("4B8C0AD8-337A-407A-9E49-074D466F837A"), + Email: email, + Active: true, + UserID: &csrUUID, }, }, }, nil) @@ -10362,7 +10409,7 @@ func createUserWithLocatorAndDODID(appCtx appcontext.AppContext, locator string, { Model: models.ServiceMember{ Edipi: models.StringPointer(dodID), - FirstName: models.StringPointer("QAECSRTestFirst"), + FirstName: models.StringPointer("QAETestFirst"), CacValidated: true, }, }, diff --git a/pkg/testdatagen/scenario/subscenarios.go b/pkg/testdatagen/scenario/subscenarios.go index 92af0431cd8..1e7334e2d09 100644 --- a/pkg/testdatagen/scenario/subscenarios.go +++ b/pkg/testdatagen/scenario/subscenarios.go @@ -316,9 +316,9 @@ func subScenarioCustomerSupportRemarks(appCtx appcontext.AppContext) func() { func subScenarioEvaluationReport(appCtx appcontext.AppContext) func() { return func() { - createQaeCsr(appCtx) + createQae(appCtx) officeUser := models.OfficeUser{} - email := "qae_csr_role@office.mil" + email := "qae_role@office.mil" err := appCtx.DB().Where("email = ?", email).First(&officeUser) if err != nil { appCtx.Logger().Panic(fmt.Errorf("failed to query OfficeUser in the DB: %w", err).Error()) @@ -571,7 +571,8 @@ func subScenarioTXOQueues(appCtx appcontext.AppContext, userUploader *uploader.U createServicesCounselor(appCtx) createTXOServicesCounselor(appCtx) createTXOServicesUSMCCounselor(appCtx) - createQaeCsr(appCtx) + createQae(appCtx) + createCustomerServiceRepresentative(appCtx) // TXO Queues createNTSMove(appCtx) diff --git a/pkg/testdatagen/testharness/make_move.go b/pkg/testdatagen/testharness/make_move.go index 8d2f3dc074e..7a8958d45af 100644 --- a/pkg/testdatagen/testharness/make_move.go +++ b/pkg/testdatagen/testharness/make_move.go @@ -19,6 +19,7 @@ import ( "github.com/transcom/mymove/pkg/gen/internalmessages" "github.com/transcom/mymove/pkg/models" routemocks "github.com/transcom/mymove/pkg/route/mocks" + "github.com/transcom/mymove/pkg/services/ghcrateengine" moverouter "github.com/transcom/mymove/pkg/services/move" mtoserviceitem "github.com/transcom/mymove/pkg/services/mto_service_item" mtoshipment "github.com/transcom/mymove/pkg/services/mto_shipment" @@ -2876,7 +2877,7 @@ func MakeHHGMoveWithApprovedNTSShipmentsForTOO(appCtx appcontext.AppContext) mod planner.On("ZipTransitDistance", mock.AnythingOfType("*appcontext.appContext"), mock.Anything, mock.Anything).Return(2361, nil) queryBuilder := query.NewQueryBuilder() - serviceItemCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter) + serviceItemCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) shipmentUpdater := mtoshipment.NewMTOShipmentStatusUpdater(queryBuilder, serviceItemCreator, planner) updatedShipments := make([]*models.MTOShipment, len(newmove.MTOShipments)) @@ -2980,7 +2981,7 @@ func MakeHHGMoveWithApprovedNTSRShipmentsForTOO(appCtx appcontext.AppContext) mo planner.On("ZipTransitDistance", mock.AnythingOfType("*appcontext.appContext"), mock.Anything, mock.Anything).Return(2361, nil) queryBuilder := query.NewQueryBuilder() - serviceItemCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter) + serviceItemCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, queryBuilder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) shipmentUpdater := mtoshipment.NewMTOShipmentStatusUpdater(queryBuilder, serviceItemCreator, planner) updatedShipments := make([]*models.MTOShipment, len(newmove.MTOShipments)) @@ -3825,7 +3826,7 @@ func MakeApprovedMoveWithPPMProgearWeightTicketOffice(appCtx appcontext.AppConte PPMShipment: models.PPMShipment{ ID: uuid.Must(uuid.NewV4()), ApprovedAt: &approvedAt, - Status: models.PPMShipmentStatusNeedsPaymentApproval, + Status: models.PPMShipmentStatusNeedsCloseout, ActualMoveDate: models.TimePointer(time.Date(testdatagen.GHCTestYear, time.March, 16, 0, 0, 0, 0, time.UTC)), ActualPickupPostalCode: models.StringPointer("42444"), ActualDestinationPostalCode: models.StringPointer("30813"), @@ -3901,7 +3902,7 @@ func MakeApprovedMoveWithPPMWeightTicketOffice(appCtx appcontext.AppContext) mod PPMShipment: models.PPMShipment{ ID: uuid.Must(uuid.NewV4()), ApprovedAt: &approvedAt, - Status: models.PPMShipmentStatusNeedsPaymentApproval, + Status: models.PPMShipmentStatusNeedsCloseout, ActualMoveDate: models.TimePointer(time.Date(testdatagen.GHCTestYear, time.March, 16, 0, 0, 0, 0, time.UTC)), ActualPickupPostalCode: models.StringPointer("42444"), ActualDestinationPostalCode: models.StringPointer("30813"), @@ -3967,7 +3968,7 @@ func MakeApprovedMoveWithPPMWeightTicketOfficeWithHHG(appCtx appcontext.AppConte PPMShipment: models.PPMShipment{ ID: uuid.Must(uuid.NewV4()), ApprovedAt: &approvedAt, - Status: models.PPMShipmentStatusNeedsPaymentApproval, + Status: models.PPMShipmentStatusNeedsCloseout, ActualMoveDate: models.TimePointer(time.Date(testdatagen.GHCTestYear, time.March, 16, 0, 0, 0, 0, time.UTC)), ActualPickupPostalCode: models.StringPointer("42444"), ActualDestinationPostalCode: models.StringPointer("30813"), @@ -4151,7 +4152,7 @@ func MakeApprovedMoveWithPPMMovingExpenseOffice(appCtx appcontext.AppContext) mo PPMShipment: models.PPMShipment{ ID: uuid.Must(uuid.NewV4()), ApprovedAt: &approvedAt, - Status: models.PPMShipmentStatusNeedsPaymentApproval, + Status: models.PPMShipmentStatusNeedsCloseout, ActualMoveDate: models.TimePointer(time.Date(testdatagen.GHCTestYear, time.March, 16, 0, 0, 0, 0, time.UTC)), ActualPickupPostalCode: models.StringPointer("42444"), ActualDestinationPostalCode: models.StringPointer("30813"), @@ -4249,7 +4250,7 @@ func MakeApprovedMoveWithPPMAllDocTypesOffice(appCtx appcontext.AppContext) mode PPMShipment: models.PPMShipment{ ID: uuid.Must(uuid.NewV4()), ApprovedAt: &approvedAt, - Status: models.PPMShipmentStatusNeedsPaymentApproval, + Status: models.PPMShipmentStatusNeedsCloseout, ActualMoveDate: models.TimePointer(time.Date(testdatagen.GHCTestYear, time.March, 16, 0, 0, 0, 0, time.UTC)), ActualPickupPostalCode: models.StringPointer("42444"), ActualDestinationPostalCode: models.StringPointer("30813"), @@ -4378,7 +4379,7 @@ func MakeApprovedMoveWithPPMShipmentAndExcessWeight(appCtx appcontext.AppContext PPMShipment: models.PPMShipment{ ID: uuid.Must(uuid.NewV4()), ApprovedAt: &approvedAt, - Status: models.PPMShipmentStatusNeedsPaymentApproval, + Status: models.PPMShipmentStatusNeedsCloseout, ActualMoveDate: models.TimePointer(time.Date(testdatagen.GHCTestYear, time.March, 16, 0, 0, 0, 0, time.UTC)), ActualPickupPostalCode: models.StringPointer("42444"), ActualDestinationPostalCode: models.StringPointer("30813"), diff --git a/playwright/tests/office/qaecsr/csrFlows.spec.js b/playwright/tests/office/qaecsr/csrFlows.spec.js index bd616b9377c..a108f89ddf0 100644 --- a/playwright/tests/office/qaecsr/csrFlows.spec.js +++ b/playwright/tests/office/qaecsr/csrFlows.spec.js @@ -13,8 +13,8 @@ test.describe('Customer Support User Flows', () => { const move = await officePage.testHarness.buildHHGMoveWithNTSAndNeedsSC(); const moveLocator = move.locator; - await officePage.signInAsNewQAECSRUser(); - await officePage.qaeCsrSearchForAndNavigateToMove(moveLocator); + await officePage.signInAsNewCustomerServiceRepresentativeUser(); + await officePage.csrSearchForAndNavigateToMove(moveLocator); // Go to Customer support remarks await page.getByText('Customer support remarks').click(); @@ -103,8 +103,8 @@ test.describe('Customer Support User Flows', () => { await page.getByText('Sign out').click(); await page.waitForURL('**/sign-in'); - await officePage.signInAsNewQAECSRUser(); - await officePage.qaeCsrSearchForAndNavigateToMove(moveLocator); + await officePage.signInAsNewCustomerServiceRepresentativeUser(); + await officePage.csrSearchForAndNavigateToMove(moveLocator); // Go to Customer support remarks await page.getByText('Customer support remarks').click(); @@ -122,8 +122,8 @@ test.describe('Customer Support User Flows', () => { const move = await officePage.testHarness.buildHHGMoveWithNTSAndNeedsSC(); const moveLocator = move.locator; - await officePage.signInAsNewQAECSRUser(); - await officePage.qaeCsrSearchForAndNavigateToMove(moveLocator); + await officePage.signInAsNewCustomerServiceRepresentativeUser(); + await officePage.csrSearchForAndNavigateToMove(moveLocator); // Navigate to view orders page await page.locator('[data-testid="view-orders"]').getByText('View orders').click(); @@ -145,8 +145,8 @@ test.describe('Customer Support User Flows', () => { const move = await officePage.testHarness.buildHHGMoveWithNTSAndNeedsSC(); const moveLocator = move.locator; - await officePage.signInAsNewQAECSRUser(); - await officePage.qaeCsrSearchForAndNavigateToMove(moveLocator); + await officePage.signInAsNewCustomerServiceRepresentativeUser(); + await officePage.csrSearchForAndNavigateToMove(moveLocator); // Navigate to view allowances page await page.locator('[data-testid="view-allowances"]').getByText('View allowances').click(); @@ -171,8 +171,8 @@ test.describe('Customer Support User Flows', () => { const move = await officePage.testHarness.buildHHGMoveWithServiceItemsandPaymentRequestReviewedForQAE(); const moveLocator = move.locator; - await officePage.signInAsNewQAECSRUser(); - await officePage.qaeCsrSearchForAndNavigateToMove(moveLocator); + await officePage.signInAsNewCustomerServiceRepresentativeUser(); + await officePage.csrSearchForAndNavigateToMove(moveLocator); await page.getByText('Payment requests').click(); diff --git a/playwright/tests/office/qaecsr/moveSearchFlows.spec.js b/playwright/tests/office/qaecsr/moveSearchFlows.spec.js index e617b4f1d48..53c09cf16a6 100644 --- a/playwright/tests/office/qaecsr/moveSearchFlows.spec.js +++ b/playwright/tests/office/qaecsr/moveSearchFlows.spec.js @@ -7,15 +7,15 @@ // @ts-check import { test, expect } from '../../utils/office/officeTest'; -test.describe('QAE/CSR Move Search', () => { +test.describe('QAE Move Search', () => { test('is able to search by move code', async ({ page, officePage }) => { const move = await officePage.testHarness.buildHHGMoveWithNTSAndNeedsSC(); const moveLocator = move.locator; - await officePage.signInAsNewQAECSRUser(); + await officePage.signInAsNewQAEUser(); // Type move code into search bar (move code is default search type) - await officePage.qaeCsrSearchForAndNavigateToMove(moveLocator); + await officePage.qaeSearchForAndNavigateToMove(moveLocator); await expect(page.locator('h1').getByText('Move details', { exact: true })).toBeVisible(); }); @@ -24,7 +24,7 @@ test.describe('QAE/CSR Move Search', () => { const moveLocator = move.locator; const { edipi } = move.Orders.ServiceMember; - await officePage.signInAsNewQAECSRUser(); + await officePage.signInAsNewQAEUser(); // Type dodID into search bar and select DOD ID as search type // @@ -61,7 +61,7 @@ test.describe('QAE/CSR Move Search', () => { const moveLocator = move.locator; const lastName = move.Orders.ServiceMember.last_name; - await officePage.signInAsNewQAECSRUser(); + await officePage.signInAsNewQAEUser(); // Type name into search bar and select name as search type // @@ -94,7 +94,7 @@ test.describe('QAE/CSR Move Search', () => { }); test('handles searches that do not return results', async ({ page, officePage }) => { - await officePage.signInAsNewQAECSRUser(); + await officePage.signInAsNewQAEUser(); // Search for a bad move code await page.locator('input[name="searchText"]').type('BAD_ID'); await page.locator('input[name="searchText"]').blur(); diff --git a/playwright/tests/office/qaecsr/qaeFlows.spec.js b/playwright/tests/office/qaecsr/qaeFlows.spec.js index 58da6ddc607..d5ca37e5b24 100644 --- a/playwright/tests/office/qaecsr/qaeFlows.spec.js +++ b/playwright/tests/office/qaecsr/qaeFlows.spec.js @@ -29,7 +29,7 @@ class QaeFlowPage extends OfficePage { * search for and navigate to move, then QA tab */ async searchForAndNavigateToMoveQATab() { - await this.qaeCsrSearchForAndNavigateToMove(this.moveLocator); + await this.qaeSearchForAndNavigateToMove(this.moveLocator); // Go to quality assurance tab await this.page.getByText('Quality assurance').click(); @@ -182,7 +182,7 @@ test.describe('Quality Evaluation Report', () => { test.beforeEach(async ({ officePage }) => { move = await officePage.testHarness.buildHHGMoveWithNTSAndNeedsSC(); - await officePage.signInAsNewQAECSRUser(); + await officePage.signInAsNewQAEUser(); qaeFlowPage = new QaeFlowPage(officePage, move.locator); await qaeFlowPage.searchForAndNavigateToMoveQATab(); }); diff --git a/playwright/tests/office/servicescounseling/servicesCounselingFlows.spec.js b/playwright/tests/office/servicescounseling/servicesCounselingFlows.spec.js index 12f36efb11c..8f6bb775041 100644 --- a/playwright/tests/office/servicescounseling/servicesCounselingFlows.spec.js +++ b/playwright/tests/office/servicescounseling/servicesCounselingFlows.spec.js @@ -347,6 +347,51 @@ test.describe('Services counselor user', () => { await expect(page.getByTestId('ShipmentContainer').getByTestId('tag')).toContainText('packet ready for download'); }); + test('is able to edit shipmentInfo and Incentives', async ({ page, scPage }) => { + const move = await scPage.testHarness.buildApprovedMoveWithPPMAllDocTypesOffice(); + await scPage.navigateToCloseoutMove(move.locator); + + // Navigate to the "Review documents" page + await expect(page.getByRole('button', { name: /Review documents/i })).toBeVisible(); + await page.getByRole('button', { name: 'Review documents' }).click(); + + await scPage.waitForPage.reviewWeightTicket(); + await expect(page.getByLabel('Accept')).toBeVisible(); + await page.getByLabel('Accept').dispatchEvent('click'); + await page.getByRole('button', { name: 'Continue' }).click(); + + await scPage.waitForPage.reviewProGear(); + await expect(page.getByLabel('Accept')).toBeVisible(); + await page.getByLabel('Accept').dispatchEvent('click'); + await page.getByRole('button', { name: 'Continue' }).click(); + + await scPage.waitForPage.reviewExpenseTicket('Packing Materials', 1, 1); + await expect(page.getByLabel('Accept')).toBeVisible(); + await page.getByLabel('Accept').dispatchEvent('click'); + await page.getByRole('button', { name: 'Continue' }).click(); + + await scPage.waitForPage.reviewDocumentsConfirmation(); + const parentShipmentInfoElement = page.locator('[data-testid="shipmentInfo"]'); + await parentShipmentInfoElement.locator('[data-testid="shipmentInfo-showRequestDetailsButton"]').click(); + + await page.getByTestId('editTextButton').dispatchEvent('click'); + await expect(page.getByText('Edit Shipment Info')).toBeVisible(); + await page.getByRole('button', { name: 'Save' }).click(); + await expect(page.getByText('Edit Shipment Info')).not.toBeVisible(); + await parentShipmentInfoElement.locator('[data-testid="shipmentInfo-showRequestDetailsButton"]').click(); + + const parentIncentivesElement = page.locator('[data-testid="incentives"]'); + await parentIncentivesElement.locator('[data-testid="incentives-showRequestDetailsButton"]').click(); + await page.getByTestId('editTextButton').dispatchEvent('click'); + await expect(page.getByText('Edit Incentives/Costs')).toBeVisible(); + await page.getByRole('button', { name: 'Save' }).click(); + await expect(page.getByText('Edit Incentives/Costs')).not.toBeVisible(); + await page.getByRole('button', { name: 'Confirm' }).click(); + await scPage.waitForPage.moveDetails(); + + await expect(page.getByTestId('ShipmentContainer').getByTestId('tag')).toContainText('packet ready for download'); + }); + test.describe('Checking for Partial/Full PPM functionality', () => { let partialPpmCloseoutLocator = ''; let partialPpmCounselingLocator = ''; diff --git a/playwright/tests/office/txo/tooFlows.spec.js b/playwright/tests/office/txo/tooFlows.spec.js index 4f27b37a513..aec2c29b705 100644 --- a/playwright/tests/office/txo/tooFlows.spec.js +++ b/playwright/tests/office/txo/tooFlows.spec.js @@ -582,7 +582,7 @@ test.describe('TOO user', () => { await tooFlowPage.waitForPage.moveDetails(); }); - // Test that the TOO is blocked from doing QAECSR actions + // Test that the TOO is blocked from doing QAE actions test('is unable to see create report buttons', async ({ page }) => { await page.getByText('Quality assurance').click(); await tooFlowPage.waitForLoading(); diff --git a/playwright/tests/utils/office/officeTest.js b/playwright/tests/utils/office/officeTest.js index 0d6e1af8ccf..25b66b22c50 100644 --- a/playwright/tests/utils/office/officeTest.js +++ b/playwright/tests/utils/office/officeTest.js @@ -17,7 +17,8 @@ export const { expect } = base; */ export const TOOOfficeUserType = 'TOO office'; export const TIOOfficeUserType = 'TIO office'; -export const QAECSROfficeUserType = 'QAE/CSR office'; +export const QAEOfficeUserType = 'QAE office'; +export const CustomerServiceRepresentativeOfficeUserType = 'CSR office'; export const ServicesCounselorOfficeUserType = 'Services Counselor office'; export const PrimeSimulatorUserType = 'Prime Simulator office'; export const MultiRoleOfficeUserType = 'Multi role office'; @@ -117,10 +118,18 @@ export class OfficePage extends BaseTestPage { } /** - * Use devlocal auth to sign in as office user with qaecsr role + * Use devlocal auth to sign in as office user with qae role */ - async signInAsNewQAECSRUser() { - await this.signInAsNewUser(QAECSROfficeUserType); + async signInAsNewQAEUser() { + await this.signInAsNewUser(QAEOfficeUserType); + await this.page.getByRole('heading', { name: 'Search for a move' }).waitFor(); + } + + /** + * Use devlocal auth to sign in as an office user with the customer service representative role + */ + async signInAsNewCustomerServiceRepresentativeUser() { + await this.signInAsNewUser(CustomerServiceRepresentativeOfficeUserType); await this.page.getByRole('heading', { name: 'Search for a move' }).waitFor(); } @@ -139,10 +148,31 @@ export class OfficePage extends BaseTestPage { } /** - * search for and navigate to move + * search for and navigate to move for QAE + * @param {string} moveLocator + */ + async qaeSearchForAndNavigateToMove(moveLocator) { + await this.page.locator('input[name="searchText"]').type(moveLocator); + await this.page.locator('input[name="searchText"]').blur(); + + await this.page.getByRole('button', { name: 'Search' }).click(); + await this.page.getByRole('heading', { name: 'Results' }).waitFor(); + + await base.expect(this.page.locator('tbody >> tr')).toHaveCount(1); + await base.expect(this.page.locator('tbody >> tr').first()).toContainText(moveLocator); + + // click result to navigate to move details page + await this.page.locator('tbody > tr').first().click(); + await this.waitForLoading(); + + base.expect(this.page.url()).toContain(`/moves/${moveLocator}/details`); + } + + /** + * search for and navigate to move for CSR * @param {string} moveLocator */ - async qaeCsrSearchForAndNavigateToMove(moveLocator) { + async csrSearchForAndNavigateToMove(moveLocator) { await this.page.locator('input[name="searchText"]').type(moveLocator); await this.page.locator('input[name="searchText"]').blur(); diff --git a/src/components/Customer/PPM/Booking/EstimatedIncentiveDetails/EstimatedIncentiveDetails.jsx b/src/components/Customer/PPM/Booking/EstimatedIncentiveDetails/EstimatedIncentiveDetails.jsx index d41008125a1..25d4960bcf5 100644 --- a/src/components/Customer/PPM/Booking/EstimatedIncentiveDetails/EstimatedIncentiveDetails.jsx +++ b/src/components/Customer/PPM/Booking/EstimatedIncentiveDetails/EstimatedIncentiveDetails.jsx @@ -2,15 +2,18 @@ import React from 'react'; import styles from 'components/Customer/PPM/Booking/EstimatedIncentiveDetails/EstimatedIncentiveDetails.module.scss'; import { ShipmentShape } from 'types/shipment'; +import { formatAddress } from 'utils/shipmentDisplay'; import { formatCentsTruncateWhole, formatCustomerDate, formatWeight } from 'utils/formatters'; const EstimatedIncentiveDetails = ({ shipment }) => { const { estimatedWeight, - pickupPostalCode, - secondaryPickupPostalCode, - destinationPostalCode, - secondaryDestinationPostalCode, + pickupAddress, + hasSecondaryPickupAddress, + secondaryPickupAddress, + destinationAddress, + hasSecondaryDestinationAddress, + secondaryDestinationAddress, expectedDepartureDate, estimatedIncentive, } = shipment?.ppmShipment || {}; @@ -23,10 +26,12 @@ const EstimatedIncentiveDetails = ({ shipment }) => {

This is an estimate of how much you could earn by moving your PPM, based on what you have entered:

diff --git a/src/components/Customer/PPM/Booking/EstimatedIncentiveDetails/EstimatedIncentiveDetails.stories.jsx b/src/components/Customer/PPM/Booking/EstimatedIncentiveDetails/EstimatedIncentiveDetails.stories.jsx index d37026f5269..e5d8bb22861 100644 --- a/src/components/Customer/PPM/Booking/EstimatedIncentiveDetails/EstimatedIncentiveDetails.stories.jsx +++ b/src/components/Customer/PPM/Booking/EstimatedIncentiveDetails/EstimatedIncentiveDetails.stories.jsx @@ -25,8 +25,20 @@ export const WithoutSecondaryPostalCodes = Template.bind({}); WithoutSecondaryPostalCodes.args = { shipment: { ppmShipment: { - pickupPostalCode: '10001', - destinationPostalCode: '10002', + pickupAddress: { + streetAddress1: '812 S 129th St', + streetAddress2: '#123', + city: 'San Antonio', + state: 'TX', + postalCode: '10001', + }, + destinationAddress: { + streetAddress1: '813 S 129th St', + streetAddress2: '#124', + city: 'San Antonio', + state: 'TX', + postalCode: '10002', + }, expectedDepartureDate: '2022-07-04', estimatedWeight: 4999, estimatedIncentive: 123499, @@ -38,10 +50,36 @@ export const WithSecondaryPostalCodes = Template.bind({}); WithSecondaryPostalCodes.args = { shipment: { ppmShipment: { - pickupPostalCode: '10001', - secondaryPickupPostalCode: '10003', - destinationPostalCode: '10002', - secondaryDestinationPostalCode: '10004', + pickupAddress: { + streetAddress1: '812 S 129th St', + streetAddress2: '#123', + city: 'San Antonio', + state: 'TX', + postalCode: '10001', + }, + destinationAddress: { + streetAddress1: '813 S 129th St', + streetAddress2: '#124', + city: 'San Antonio', + state: 'TX', + postalCode: '10002', + }, + secondaryPickupAddress: { + streetAddress1: '814 S 129th St', + streetAddress2: '#125', + city: 'San Antonio', + state: 'TX', + postalCode: '10001', + }, + secondaryDestinationAddress: { + streetAddress1: '815 S 129th St', + streetAddress2: '#126', + city: 'San Antonio', + state: 'TX', + postalCode: '10002', + }, + hasSecondaryDestinationAddress: true, + hasSecondaryPickupAddress: true, expectedDepartureDate: '2022-07-04', estimatedWeight: 4999, estimatedIncentive: 123499, diff --git a/src/components/Customer/PPM/Booking/EstimatedIncentiveDetails/EstimatedIncentiveDetails.test.jsx b/src/components/Customer/PPM/Booking/EstimatedIncentiveDetails/EstimatedIncentiveDetails.test.jsx index b3e7d48355b..cf95a1de63a 100644 --- a/src/components/Customer/PPM/Booking/EstimatedIncentiveDetails/EstimatedIncentiveDetails.test.jsx +++ b/src/components/Customer/PPM/Booking/EstimatedIncentiveDetails/EstimatedIncentiveDetails.test.jsx @@ -7,8 +7,20 @@ const defaultProps = { shipment: { id: '1234', ppmShipment: { - pickupPostalCode: '10001', - destinationPostalCode: '10002', + pickupAddress: { + streetAddress1: '812 S 129th St', + streetAddress2: '#123', + city: 'San Antonio', + state: 'TX', + postalCode: '10001', + }, + destinationAddress: { + streetAddress1: '813 S 129th St', + streetAddress2: '#124', + city: 'San Antonio', + state: 'TX', + postalCode: '10002', + }, expectedDepartureDate: '2022-07-04', estimatedWeight: 3456, proGearWeight: 1333, @@ -22,10 +34,36 @@ const optionalSecondaryProps = { shipment: { id: '1234', ppmShipment: { - pickupPostalCode: '10001', - destinationPostalCode: '10002', - secondaryPickupPostalCode: '10003', - secondaryDestinationPostalCode: '10004', + pickupAddress: { + streetAddress1: '812 S 129th St', + streetAddress2: '#123', + city: 'San Antonio', + state: 'TX', + postalCode: '10001', + }, + destinationAddress: { + streetAddress1: '813 S 129th St', + streetAddress2: '#124', + city: 'San Antonio', + state: 'TX', + postalCode: '10002', + }, + secondaryPickupAddress: { + streetAddress1: '813 S 129th St', + streetAddress2: '#125', + city: 'San Antonio', + state: 'TX', + postalCode: '10003', + }, + secondaryDestinationAddress: { + streetAddress1: '814 S 129th St', + streetAddress2: '#126', + city: 'San Antonio', + state: 'TX', + postalCode: '10004', + }, + hasSecondaryPickupAddress: true, + hasSecondaryDestinationAddress: true, expectedDepartureDate: '2022-07-04', estimatedWeight: 3456, proGearWeight: 1333, @@ -49,8 +87,8 @@ describe('EstimatedIncentiveDetails component', () => { const incentiveListItems = screen.getAllByRole('listitem'); expect(incentiveListItems).toHaveLength(4); expect(incentiveListItems[0]).toHaveTextContent('3,456 lbs estimated weight'); - expect(incentiveListItems[1]).toHaveTextContent('Starting from 10001'); - expect(incentiveListItems[2]).toHaveTextContent('Ending in 10002'); + expect(incentiveListItems[1]).toHaveTextContent('Starting from 812 S 129th St, #123, San Antonio, TX 10001'); + expect(incentiveListItems[2]).toHaveTextContent('Ending at 813 S 129th St, #124, San Antonio, TX 10002'); expect(incentiveListItems[3]).toHaveTextContent('Starting your PPM on 04 Jul 2022'); expect(screen.getByRole('heading', { level: 3 })).toHaveTextContent('Your actual incentive amount will vary'); @@ -74,10 +112,12 @@ describe('EstimatedIncentiveDetails component', () => { const incentiveListItems = screen.getAllByRole('listitem'); expect(incentiveListItems).toHaveLength(6); expect(incentiveListItems[0]).toHaveTextContent('3,456 lbs estimated weight'); - expect(incentiveListItems[1]).toHaveTextContent('Starting from 10001'); - expect(incentiveListItems[2]).toHaveTextContent('Picking up things in 10003'); - expect(incentiveListItems[3]).toHaveTextContent('Dropping off things in 10004'); - expect(incentiveListItems[4]).toHaveTextContent('Ending in 10002'); + expect(incentiveListItems[1]).toHaveTextContent('Starting from 812 S 129th St, #123, San Antonio, TX 10001'); + expect(incentiveListItems[2]).toHaveTextContent('Picking up things at 813 S 129th St, #125, San Antonio, TX 10003'); + expect(incentiveListItems[3]).toHaveTextContent( + 'Dropping off things at 814 S 129th St, #126, San Antonio, TX 10004', + ); + expect(incentiveListItems[4]).toHaveTextContent('Ending at 813 S 129th St, #124, San Antonio, TX 10002'); expect(incentiveListItems[5]).toHaveTextContent('Starting your PPM on 04 Jul 2022'); }); }); diff --git a/src/components/DocumentViewer/Content/Content.jsx b/src/components/DocumentViewer/Content/Content.jsx index 2be45bc0bed..2345f79b635 100644 --- a/src/components/DocumentViewer/Content/Content.jsx +++ b/src/components/DocumentViewer/Content/Content.jsx @@ -43,27 +43,3 @@ DocViewerContent.propTypes = { }; export default DocViewerContent; - -/** - * TODO - * - * - add className prop to file viewer - * - add rotate left/right: - * - - * - implement pagination for multi-page PDFs & nav render prop: - *
- - -
-*/ diff --git a/src/components/Office/AllowancesDetailForm/AllowancesDetailForm.jsx b/src/components/Office/AllowancesDetailForm/AllowancesDetailForm.jsx index dcfff64ac72..8909d8ae06e 100644 --- a/src/components/Office/AllowancesDetailForm/AllowancesDetailForm.jsx +++ b/src/components/Office/AllowancesDetailForm/AllowancesDetailForm.jsx @@ -104,7 +104,7 @@ const AllowancesDetailForm = ({ header, entitlements, branchOptions, formIsDisab
Weight allowance
-
{formatWeight(entitlements.authorizedWeight)}
+
{formatWeight(entitlements.totalWeight)}
{ const validationSchema = Yup.object().shape({ @@ -38,15 +39,14 @@ const CustomerContactInfoForm = ({ initialValues, onSubmit, onBack }) => { .required('Required'), // min 12 includes hyphens phoneIsPreferred: Yup.boolean(), emailIsPreferred: Yup.boolean(), + cacUser: Yup.boolean().required('Required'), }); - return (
-

Customer Info

- {({ isValid, isSubmitting, handleSubmit }) => { + {({ isValid, handleSubmit }) => { return ( @@ -74,10 +74,42 @@ const CustomerContactInfoForm = ({ initialValues, onSubmit, onBack }) => { + +

CAC Validation

+ + + Is the customer a non-CAC user or do they need to bypass CAC validation? + + + If this is checked yes, then the customer has already validated their CAC or their identity has + been validated by a trusted office user. + +
+ + +
+
+
@@ -104,6 +136,7 @@ CustomerContactInfoForm.propTypes = { telephone: PropTypes.string, email: PropTypes.string, customerAddress: ResidentialAddressShape, + cacUser: PropTypes.bool, }).isRequired, onSubmit: PropTypes.func, onBack: PropTypes.func, diff --git a/src/components/Office/CustomerContactInfoForm/CustomerContactInfoForm.test.jsx b/src/components/Office/CustomerContactInfoForm/CustomerContactInfoForm.test.jsx index 3cee7e17fbd..99566b44b8e 100644 --- a/src/components/Office/CustomerContactInfoForm/CustomerContactInfoForm.test.jsx +++ b/src/components/Office/CustomerContactInfoForm/CustomerContactInfoForm.test.jsx @@ -22,6 +22,7 @@ describe('CustomerContactInfoForm Component', () => { name: '', telephone: '', email: '', + cacUser: true, }; const testProps = { initialValues, @@ -29,6 +30,31 @@ describe('CustomerContactInfoForm Component', () => { onBack: jest.fn(), }; + const initialValuesCacValidated = { + firstName: 'joe', + middleName: 'bob', + lastName: 'bob', + suffix: 'jr', + customerTelephone: '855-222-1111', + customerEmail: 'joebob@gmail.com', + customerAddress: { + streetAddress1: '123 Happy St', + streetAddress2: 'Unit 4', + city: 'Missoula', + state: 'MT', + postalCode: '59802', + }, + name: 'joe bob', + telephone: '855-222-1111', + email: 'joebob@gmail.com', + cacUser: null, + }; + const testPropsCacValidated = { + initialValuesCacValidated, + onSubmit: jest.fn(), + onBack: jest.fn(), + }; + it('renders the form inputs', async () => { render(); @@ -63,6 +89,38 @@ describe('CustomerContactInfoForm Component', () => { expect(screen.getByLabelText('Name')).toBeInstanceOf(HTMLInputElement); expect(screen.getAllByLabelText('Phone')[1]).toBeInstanceOf(HTMLInputElement); expect(screen.getAllByLabelText('Email')[1]).toBeInstanceOf(HTMLInputElement); + + expect(screen.getByText('CAC Validation')).toBeInstanceOf(HTMLHeadingElement); + expect( + screen.getByText('Is the customer a non-CAC user or do they need to bypass CAC validation?'), + ).toBeInTheDocument(); + expect( + screen.getByText( + 'If this is checked yes, then the customer has already validated their CAC or their identity has been validated by a trusted office user.', + ), + ).toBeInTheDocument(); + expect(screen.getByTestId('cac-user-yes')).toBeInTheDocument(); + expect(screen.getByTestId('cac-user-no')).toBeInTheDocument(); + }); + }); + + it('does not allow submission without cac_validated value', async () => { + render(); + + await waitFor(() => { + expect(screen.getByText('CAC Validation')).toBeInstanceOf(HTMLHeadingElement); + expect( + screen.getByText('Is the customer a non-CAC user or do they need to bypass CAC validation?'), + ).toBeInTheDocument(); + expect( + screen.getByText( + 'If this is checked yes, then the customer has already validated their CAC or their identity has been validated by a trusted office user.', + ), + ).toBeInTheDocument(); + expect(screen.getByTestId('cac-user-yes')).toBeInTheDocument(); + expect(screen.getByTestId('cac-user-no')).toBeInTheDocument(); }); + expect(screen.getByRole('button', { name: 'Save' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: 'Save' })).toBeDisabled(); }); }); diff --git a/src/components/Office/CustomerSupportRemarkForm/CustomerSupportRemarkForm.test.jsx b/src/components/Office/CustomerSupportRemarkForm/CustomerSupportRemarkForm.test.jsx index 9f2ef729dc2..af06d840e6e 100644 --- a/src/components/Office/CustomerSupportRemarkForm/CustomerSupportRemarkForm.test.jsx +++ b/src/components/Office/CustomerSupportRemarkForm/CustomerSupportRemarkForm.test.jsx @@ -17,9 +17,9 @@ beforeEach(() => { jest.clearAllMocks(); }); -const testState = { +const qaeTestState = { auth: { - activeRole: roleTypes.QAE_CSR, + activeRole: roleTypes.QAE, isLoading: false, isLoggedIn: true, }, @@ -27,7 +27,30 @@ const testState = { user: { userId123: { id: 'userId123', - roles: [{ roleType: roleTypes.QAE_CSR }], + roles: [{ roleType: roleTypes.QAE }], + office_user: { + first_name: 'Amanda', + last_name: 'Gorman', + transportation_office: { + gbloc: 'ABCD', + }, + }, + }, + }, + }, +}; + +const csrTestState = { + auth: { + activeRole: roleTypes.CUSTOMER_SERVICE_REPRESENTATIVE, + isLoading: false, + isLoggedIn: true, + }, + entities: { + user: { + userId123: { + id: 'userId123', + roles: [{ roleType: roleTypes.CUSTOMER_SERVICE_REPRESENTATIVE }], office_user: { first_name: 'Amanda', last_name: 'Gorman', @@ -41,9 +64,20 @@ const testState = { }; describe('CustomerSupportRemarkForm', () => { - it('renders the form', async () => { + it('qae can render the form', async () => { + render( + + + , + ); + + expect(await screen.findByTestId('form')).toBeInTheDocument(); + expect(await screen.findByTestId('textarea')).toBeInTheDocument(); + expect(await screen.findByTestId('button')).toBeInTheDocument(); + }); + it('csr can render the form', async () => { render( - + , ); @@ -53,11 +87,41 @@ describe('CustomerSupportRemarkForm', () => { expect(await screen.findByTestId('button')).toBeInTheDocument(); }); - it('submits the form with expected data', async () => { + it('qae can submit the form with expected data', async () => { + // Spy on and mock mutation function + const mutationSpy = jest.spyOn(api, 'createCustomerSupportRemarkForMove').mockImplementation(() => {}); + render( + + + , + ); + + // Type in the textarea + await userEvent.type(await screen.findByTestId('textarea'), 'Test Remark'); + await waitFor(() => { + expect(screen.getByTestId('button').hasAttribute('disabled')).toBeFalsy(); + }); + + // Submit the form + await waitFor(() => { + fireEvent.click(screen.getByRole('button', { name: 'Save' })); + }); + + // Ensure the expected mutation was called with expected data + expect(mutationSpy).toHaveBeenCalledTimes(1); + expect(mutationSpy).toHaveBeenCalledWith({ + body: { + content: 'Test Remark', + }, + locator: 'LR4T8V', + }); + }); + + it('csr can submit the form with expected data', async () => { // Spy on and mock mutation function const mutationSpy = jest.spyOn(api, 'createCustomerSupportRemarkForMove').mockImplementation(() => {}); render( - + , ); @@ -83,12 +147,31 @@ describe('CustomerSupportRemarkForm', () => { }); }); - it('will not submit empty remarks', async () => { + it('qae will not submit empty remarks', async () => { + // Spy on and mock mutation function + const mutationSpy = jest.spyOn(api, 'createCustomerSupportRemarkForMove').mockImplementation(() => {}); + + render( + + + , + ); + + // Submit the empty form + await waitFor(() => { + fireEvent.click(screen.getByRole('button', { name: 'Save' })); + }); + + // Ensure the expected mutation was called with expected data + expect(mutationSpy).toHaveBeenCalledTimes(0); + }); + + it('csr will not submit empty remarks', async () => { // Spy on and mock mutation function const mutationSpy = jest.spyOn(api, 'createCustomerSupportRemarkForMove').mockImplementation(() => {}); render( - + , ); @@ -106,7 +189,7 @@ describe('CustomerSupportRemarkForm', () => { // Spy on and mock mutation function const isMoveLocked = true; render( - + , ); diff --git a/src/components/Office/DefinitionLists/AllowancesList.jsx b/src/components/Office/DefinitionLists/AllowancesList.jsx index 8f62f2bf63d..892204ab28a 100644 --- a/src/components/Office/DefinitionLists/AllowancesList.jsx +++ b/src/components/Office/DefinitionLists/AllowancesList.jsx @@ -22,7 +22,7 @@ const AllowancesList = ({ info, showVisualCues }) => {
Weight allowance
-
{formatWeight(info.authorizedWeight)}
+
{formatWeight(info.totalWeight)}
Storage in transit (SIT)
@@ -63,8 +63,7 @@ AllowancesList.propTypes = { info: PropTypes.shape({ branch: PropTypes.string, grade: PropTypes.string, - weightAllowance: PropTypes.number, - authorizedWeight: PropTypes.number, + totalWeight: PropTypes.string, progear: PropTypes.number, spouseProgear: PropTypes.number, storageInTransit: PropTypes.number, diff --git a/src/components/Office/DefinitionLists/AllowancesList.stories.jsx b/src/components/Office/DefinitionLists/AllowancesList.stories.jsx index d7ced60a555..6ee3694d760 100644 --- a/src/components/Office/DefinitionLists/AllowancesList.stories.jsx +++ b/src/components/Office/DefinitionLists/AllowancesList.stories.jsx @@ -16,7 +16,7 @@ export default { const info = { branch: 'NAVY', grade: 'E_6', - weightAllowance: 11000, + totalWeight: 11000, authorizedWeight: 11000, progear: 2000, spouseProgear: 500, diff --git a/src/components/Office/DefinitionLists/AllowancesList.test.jsx b/src/components/Office/DefinitionLists/AllowancesList.test.jsx index e72b9fd320b..3ce9df787a8 100644 --- a/src/components/Office/DefinitionLists/AllowancesList.test.jsx +++ b/src/components/Office/DefinitionLists/AllowancesList.test.jsx @@ -8,6 +8,7 @@ const info = { grade: 'E_6', weightAllowance: 12000, authorizedWeight: 11000, + totalWeight: 12000, progear: 2000, spouseProgear: 500, storageInTransit: 90, @@ -24,7 +25,7 @@ describe('AllowancesList', () => { it('renders formatted weight allowance', () => { render(); - expect(screen.getByText('11,000 lbs')).toBeInTheDocument(); + expect(screen.getByText('12,000 lbs')).toBeInTheDocument(); }); it('renders storage in transit', () => { diff --git a/src/components/Office/DefinitionLists/PPMShipmentInfoList.jsx b/src/components/Office/DefinitionLists/PPMShipmentInfoList.jsx index c22ae03e3f1..c9b6cea92a2 100644 --- a/src/components/Office/DefinitionLists/PPMShipmentInfoList.jsx +++ b/src/components/Office/DefinitionLists/PPMShipmentInfoList.jsx @@ -254,7 +254,7 @@ const PPMShipmentInfoList = ({ {hasRequestedAdvanceElement} {hasRequestedAdvance === true && advanceStatusElement} {advanceStatus === ADVANCE_STATUSES.APPROVED.apiValue && aoaPacketElement} - {status === ppmShipmentStatuses.PAYMENT_APPROVED && paymentPacketElement} + {status === ppmShipmentStatuses.CLOSEOUT_COMPLETE && paymentPacketElement} {counselorRemarksElement} ); diff --git a/src/components/Office/DefinitionLists/PPMShipmentInfoList.test.jsx b/src/components/Office/DefinitionLists/PPMShipmentInfoList.test.jsx index 9dd839ea5db..32a0e04e385 100644 --- a/src/components/Office/DefinitionLists/PPMShipmentInfoList.test.jsx +++ b/src/components/Office/DefinitionLists/PPMShipmentInfoList.test.jsx @@ -127,7 +127,7 @@ describe('PPMShipmentInfoList', () => { }; downloadPPMPaymentPacket.mockImplementation(() => Promise.resolve(mockResponse)); - renderWithPermissions({ ppmShipment: { status: ppmShipmentStatuses.PAYMENT_APPROVED } }); + renderWithPermissions({ ppmShipment: { status: ppmShipmentStatuses.CLOSEOUT_COMPLETE } }); expect(screen.getByText('Download Payment Packet (PDF)', { exact: false })).toBeInTheDocument(); @@ -146,7 +146,7 @@ describe('PPMShipmentInfoList', () => { response: { body: { title: 'Error title', detail: 'Error detail' } }, }); - const shipment = { ppmShipment: { status: ppmShipmentStatuses.PAYMENT_APPROVED } }; + const shipment = { ppmShipment: { status: ppmShipmentStatuses.CLOSEOUT_COMPLETE } }; const onErrorHandler = jest.fn(); render( diff --git a/src/components/Office/EvaluationForm/EvaluationForm.test.jsx b/src/components/Office/EvaluationForm/EvaluationForm.test.jsx index cce6c4494a8..767381cde3f 100644 --- a/src/components/Office/EvaluationForm/EvaluationForm.test.jsx +++ b/src/components/Office/EvaluationForm/EvaluationForm.test.jsx @@ -38,7 +38,7 @@ const mockEvaluationReport = { moveID: '551dd01f-90cf-44d6-addb-ff919433dd61', moveReferenceID: '4118-8295', officeUser: { - email: 'qae_csr_role@office.mil', + email: 'qae_role@office.mil', firstName: 'Leo', id: 'ef4f6d1f-4ac3-4159-a364-5403e7d958ff', lastName: 'Spaceman', diff --git a/src/components/Office/EvaluationReportPreview/EvaluationReportPreview.test.jsx b/src/components/Office/EvaluationReportPreview/EvaluationReportPreview.test.jsx index e08620a478b..4ebd2f9e64d 100644 --- a/src/components/Office/EvaluationReportPreview/EvaluationReportPreview.test.jsx +++ b/src/components/Office/EvaluationReportPreview/EvaluationReportPreview.test.jsx @@ -205,7 +205,7 @@ const evaluationReport = { moveID: '01912827-b4e5-46cb-a800-4273830956cd', moveReferenceID: '1018-3234', officeUser: { - email: 'qae_csr_role@office.mil', + email: 'qae_role@office.mil', firstName: 'Leo', id: 'ef4f6d1f-4ac3-4159-a364-5403e7d958ff', lastName: 'Spaceman', diff --git a/src/components/Office/ExpandableServiceItemRow/ExpandableServiceItemRow.jsx b/src/components/Office/ExpandableServiceItemRow/ExpandableServiceItemRow.jsx index bd4bd4f2ffd..d5d39cf7a63 100644 --- a/src/components/Office/ExpandableServiceItemRow/ExpandableServiceItemRow.jsx +++ b/src/components/Office/ExpandableServiceItemRow/ExpandableServiceItemRow.jsx @@ -56,6 +56,7 @@ const ExpandableServiceItemRow = ({ )} {serviceItem.mtoServiceItemName} + {additionalServiceItemData.standaloneCrate && ' - Standalone'} {toDollarString(formatCents(serviceItem.priceCents))} diff --git a/src/components/Office/OrdersDetailForm/OrdersDetailForm.jsx b/src/components/Office/OrdersDetailForm/OrdersDetailForm.jsx index 5b375fa179c..5373b89154c 100644 --- a/src/components/Office/OrdersDetailForm/OrdersDetailForm.jsx +++ b/src/components/Office/OrdersDetailForm/OrdersDetailForm.jsx @@ -3,7 +3,7 @@ import { func, string, bool } from 'prop-types'; import styles from './OrdersDetailForm.module.scss'; -import { formatLabelReportByDate } from 'utils/formatters'; +import { dropdownInputOptions, formatLabelReportByDate } from 'utils/formatters'; import { CheckboxField, DropdownInput, DatePickerInput, DutyLocationInput } from 'components/form/fields'; import TextField from 'components/form/fields/TextField/TextField'; import MaskedTextField from 'components/form/fields/MaskedTextField/MaskedTextField'; @@ -74,12 +74,12 @@ const OrdersDetailForm = ({ { setFormOrdersType(e.target.value); setFieldValue('ordersType', e.target.value); }} - isDisabled={formIsDisabled} + isDisabled={formIsDisabled || formOrdersType === 'SAFETY'} /> {showOrdersTypeDetail && ( { expect(await screen.findByLabelText('Date of separation')).toBeInTheDocument(); expect(await screen.findByLabelText('HOR, HOS or PLEAD')).toBeInTheDocument(); }); + + it('has orders type dropdown disabled if safety move', async () => { + renderOrdersDetailForm({ + showDepartmentIndicator: false, + showOrdersNumber: false, + showOrdersTypeDetail: false, + showHHGTac: false, + showHHGSac: false, + showNTSTac: false, + showNTSSac: false, + showOrdersAcknowledgement: false, + ordersType: 'SAFETY', + }); + + // correct labels are visible + expect(await screen.findByLabelText('Orders type')).toBeDisabled(); + }); }); diff --git a/src/components/Office/PPM/PPMHeaderSummary/EditPPMHeaderSummaryModal.jsx b/src/components/Office/PPM/PPMHeaderSummary/EditPPMHeaderSummaryModal.jsx new file mode 100644 index 00000000000..9a12325d96a --- /dev/null +++ b/src/components/Office/PPM/PPMHeaderSummary/EditPPMHeaderSummaryModal.jsx @@ -0,0 +1,121 @@ +import React from 'react'; +import { Formik } from 'formik'; +import PropTypes from 'prop-types'; +import * as Yup from 'yup'; +import { Button } from '@trussworks/react-uswds'; + +import styles from './EditPPMHeaderSummaryModal.module.scss'; + +import { formatCentsTruncateWhole } from 'utils/formatters'; +import { Form } from 'components/form'; +import { ModalContainer, Overlay } from 'components/MigratedModal/MigratedModal'; +import { DatePickerInput } from 'components/form/fields'; +import MaskedTextField from 'components/form/fields/MaskedTextField/MaskedTextField'; +import Modal, { ModalActions, ModalClose, ModalTitle } from 'components/Modal/Modal'; + +const EditPPMHeaderSummaryModal = ({ sectionType, sectionInfo, onClose, onSubmit, editItemName }) => { + const { actualMoveDate, advanceAmountReceived } = sectionInfo; + let title = 'Edit'; + if (sectionType === 'shipmentInfo') { + title = 'Edit Shipment Info'; + } else if (sectionType === 'incentives') { + title = 'Edit Incentives/Costs'; + } + const initialValues = { + editItemName, + actualMoveDate: actualMoveDate || '', + advanceAmountReceived: formatCentsTruncateWhole(advanceAmountReceived).replace(/,/g, ''), + }; + + const validationSchema = Yup.object().shape({ + actualMoveDate: Yup.date() + .typeError('Enter a complete date in DD MMM YYYY format (day, month, year).') + .when('editItemName', { + is: 'actualMoveDate', + then: (schema) => schema.required('Required').max(new Date(), 'Date cannot be in the future'), + }), + advanceAmountReceived: Yup.number().when('editItemName', { + is: 'advanceAmountReceived', + then: (schema) => schema.required('Required'), + }), + }); + + return ( +
+ + + + onClose()} /> + +

{title}

+
+ + {({ isValid }) => { + return ( + +
+ {editItemName === 'actualMoveDate' && ( + + )} + {editItemName === 'advanceAmountReceived' && ( + + )} +
+ + + + + + ); + }} +
+
+
+
+ ); +}; + +EditPPMHeaderSummaryModal.propTypes = { + sectionType: PropTypes.string.isRequired, + sectionInfo: PropTypes.shape({ + actualMoveDate: PropTypes.string, + advanceAmountReceived: PropTypes.number, + }), + onClose: PropTypes.func.isRequired, + onSubmit: PropTypes.func.isRequired, + editItemName: PropTypes.string.isRequired, +}; + +EditPPMHeaderSummaryModal.defaultProps = { + sectionInfo: { + actualMoveDate: '', + advanceAmountReceived: 0, + }, +}; +export default EditPPMHeaderSummaryModal; diff --git a/src/components/Office/PPM/PPMHeaderSummary/EditPPMHeaderSummaryModal.module.scss b/src/components/Office/PPM/PPMHeaderSummary/EditPPMHeaderSummaryModal.module.scss new file mode 100644 index 00000000000..f07e76c97a6 --- /dev/null +++ b/src/components/Office/PPM/PPMHeaderSummary/EditPPMHeaderSummaryModal.module.scss @@ -0,0 +1,36 @@ +@import 'shared/styles/colors.scss'; +@import 'shared/styles/basics'; + +.EditPPMHeaderSummaryModal { + max-height: 90vh; + + .ModalPanel { + @include u-border('base-lighter'); + @include u-border('1px'); + @include u-radius('05'); + @include u-padding(3); + display: flex; + + .reasonDropdown label { + @include u-margin-top(0); + } + } + + .CancelButton { + @include u-bg('transparent'); + } + .errors { + margin-top: 0; + color: #b50909; + font-weight: 700; + font-size: 15px; + padding: 4px 0px; + } + + .ModalTitle { + h2 { + font-size: 1.87rem; + color: $base-darker; + } + } +} \ No newline at end of file diff --git a/src/components/Office/PPM/PPMHeaderSummary/EditPPMHeaderSummaryModal.stories.jsx b/src/components/Office/PPM/PPMHeaderSummary/EditPPMHeaderSummaryModal.stories.jsx new file mode 100644 index 00000000000..1f0dd690cfb --- /dev/null +++ b/src/components/Office/PPM/PPMHeaderSummary/EditPPMHeaderSummaryModal.stories.jsx @@ -0,0 +1,46 @@ +import React from 'react'; +import { action } from '@storybook/addon-actions'; + +import EditPPMHeaderSummaryModal from './EditPPMHeaderSummaryModal'; + +export default { + title: 'Office Components/EditPPMHeaderSummaryModal', + component: EditPPMHeaderSummaryModal, +}; + +// Mock data for the story +const sectionInfo = { + actualMoveDate: '2022-01-01', + advanceAmountReceived: 50000, +}; + +export const Basic = (args) => { + return ; +}; + +export const Default = Basic.bind({}); +Default.args = { + sectionType: 'shipmentInfo', + sectionInfo, + onClose: action('onClose'), + onSubmit: action('onSubmit'), + editItemName: 'actualMoveDate', +}; + +export const EditShipmentInfo = Basic.bind({}); +EditShipmentInfo.args = { + sectionType: 'shipmentInfo', + sectionInfo, + onClose: action('onClose'), + onSubmit: action('onSubmit'), + editItemName: 'actualMoveDate', +}; + +export const EditIncentives = Basic.bind({}); +EditIncentives.args = { + sectionType: 'incentives', + sectionInfo, + onClose: action('onClose'), + onSubmit: action('onSubmit'), + editItemName: 'advanceAmountReceived', +}; diff --git a/src/components/Office/PPM/PPMHeaderSummary/EditPPMHeaderSummaryModal.test.jsx b/src/components/Office/PPM/PPMHeaderSummary/EditPPMHeaderSummaryModal.test.jsx new file mode 100644 index 00000000000..764792ec2d1 --- /dev/null +++ b/src/components/Office/PPM/PPMHeaderSummary/EditPPMHeaderSummaryModal.test.jsx @@ -0,0 +1,153 @@ +import React from 'react'; +import { render, screen, waitFor, act } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + +import EditPPMHeaderSummaryModal from './EditPPMHeaderSummaryModal'; + +let onClose; +let onSubmit; +beforeEach(() => { + onClose = jest.fn(); + onSubmit = jest.fn(); +}); + +afterEach(() => { + jest.clearAllMocks(); +}); + +describe('EditPPMHeaderSummaryModal', () => { + const sectionInfo = { + actualMoveDate: '2022-01-01', + advanceAmountReceived: 50000, + }; + + it('renders the component', async () => { + await act(async () => { + render( + , + ); + }); + + expect(await screen.findByRole('heading', { level: 3, name: 'Edit Shipment Info' })).toBeInTheDocument(); + expect(screen.getByLabelText('Actual move start date')).toBeInTheDocument(); + expect(screen.getByRole('button', { name: 'Save' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: 'Cancel' })).toBeInTheDocument(); + expect(screen.getByLabelText('Close')).toBeInstanceOf(HTMLButtonElement); + }); + + it('closes the modal when close icon is clicked', async () => { + await act(async () => { + render( + , + ); + }); + + await act(async () => { + await userEvent.click(await screen.getByLabelText('Close')); + }); + + await waitFor(() => { + expect(onClose).toHaveBeenCalledTimes(1); + }); + }); + + it('closes the modal when the cancel button is clicked', async () => { + await act(async () => { + render( + , + ); + }); + + await act(async () => { + await userEvent.click(await screen.getByRole('button', { name: 'Cancel' })); + }); + + await waitFor(() => { + expect(onClose).toHaveBeenCalledTimes(1); + }); + }); + + it('calls the submit function when submit button is clicked', async () => { + await act(async () => { + render( + , + ); + }); + + await act(async () => { + await userEvent.click(await screen.getByRole('button', { name: 'Save' })); + }); + + await waitFor(() => { + expect(onSubmit).toHaveBeenCalled(); + }); + }); + + it('displays required validation error when actual move date is empty', async () => { + await act(async () => { + render( + , + ); + }); + + await act(async () => { + await userEvent.clear(await screen.getByLabelText('Actual move start date')); + await userEvent.click(await screen.getByRole('button', { name: 'Save' })); + }); + + expect(await screen.findByText('Required')).toBeInTheDocument(); + expect(screen.getByRole('button', { name: 'Save' })).toHaveAttribute('disabled'); + }); + + it('displays required validation error when advance amount received is empty', async () => { + await act(async () => { + render( + , + ); + }); + + await act(async () => { + await userEvent.clear(await screen.getByLabelText('Advance received')); + await userEvent.click(await screen.getByRole('button', { name: 'Save' })); + }); + + expect(await screen.findByText('Required')).toBeInTheDocument(); + expect(screen.getByRole('button', { name: 'Save' })).toHaveAttribute('disabled'); + }); +}); diff --git a/src/components/Office/PPM/PPMHeaderSummary/HeaderSection.jsx b/src/components/Office/PPM/PPMHeaderSummary/HeaderSection.jsx index 651c5389823..37fa23a3dbf 100644 --- a/src/components/Office/PPM/PPMHeaderSummary/HeaderSection.jsx +++ b/src/components/Office/PPM/PPMHeaderSummary/HeaderSection.jsx @@ -1,11 +1,17 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; +import { useParams } from 'react-router-dom'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Label, Button, Alert } from '@trussworks/react-uswds'; +import { useQueryClient, useMutation, useIsFetching } from '@tanstack/react-query'; import classnames from 'classnames'; import styles from './HeaderSection.module.scss'; +import EditPPMHeaderSummaryModal from 'components/Office/PPM/PPMHeaderSummary/EditPPMHeaderSummaryModal'; import { formatDate, formatCents, formatWeight } from 'utils/formatters'; +import { MTO_SHIPMENTS, PPMCLOSEOUT } from 'constants/queryKeys'; +import { updateMTOShipment } from 'services/ghcApi'; +import { useEditShipmentQueries, usePPMShipmentDocsQueries } from 'hooks/queries'; export const sectionTypes = { incentives: 'incentives', @@ -31,12 +37,24 @@ const getSectionTitle = (sectionInfo) => { } }; +const OpenModalButton = ({ onClick, isDisabled }) => ( + +); + // Returns the markup needed for a specific section -const getSectionMarkup = (sectionInfo) => { - const aoaRequestedValue = sectionInfo.isAdvanceRequested - ? `$${formatCents(sectionInfo.advanceAmountRequested)}` - : 'No'; - const aoaValue = sectionInfo.isAdvanceReceived ? `$${formatCents(sectionInfo.advanceAmountReceived)}` : 'No'; +const getSectionMarkup = (sectionInfo, handleEditOnClick, isFetchingItems, updatedItemName) => { + const aoaRequestedValue = `$${formatCents(sectionInfo.advanceAmountRequested)}`; + const aoaValue = `$${formatCents(sectionInfo.advanceAmountReceived)}`; const renderHaulType = (haulType) => { return haulType === HAUL_TYPES.LINEHAUL ? 'Linehaul' : 'Shorthaul'; @@ -52,15 +70,27 @@ const getSectionMarkup = (sectionInfo) => {
- {formatDate(sectionInfo.actualMoveDate, null, 'DD-MMM-YYYY')} + + {isFetchingItems && updatedItemName === 'actualMoveDate' ? ( + + ) : ( + <> + {formatDate(sectionInfo.actualMoveDate, null, 'DD-MMM-YYYY')} + handleEditOnClick(sectionInfo.type, 'actualMoveDate')} + isDisabled={isFetchingItems} + /> + + )} +
- - {sectionInfo.actualPickupPostalCode} + + {sectionInfo.pickupAddress}
- - {sectionInfo.actualDestinationPostalCode} + + {sectionInfo.destinationAddress}
@@ -83,13 +113,21 @@ const getSectionMarkup = (sectionInfo) => {
- ${formatCents(sectionInfo.gcc)} + {isFetchingItems && updatedItemName === 'actualMoveDate' ? ( + + ) : ( + `$${formatCents(sectionInfo.gcc)}` + )}
- ${formatCents(sectionInfo.grossIncentive)} + {isFetchingItems && updatedItemName === 'actualMoveDate' ? ( + + ) : ( + `$${formatCents(sectionInfo.grossIncentive)}` + )}
@@ -101,13 +139,27 @@ const getSectionMarkup = (sectionInfo) => {
- {aoaValue} + {isFetchingItems && updatedItemName === 'advanceAmountReceived' ? ( + + ) : ( + <> + {aoaValue} + handleEditOnClick(sectionInfo.type, 'advanceAmountReceived')} + isDisabled={isFetchingItems} + /> + + )}
- ${formatCents(sectionInfo.remainingIncentive)} + {isFetchingItems && updatedItemName ? ( + + ) : ( + `$${formatCents(sectionInfo.remainingIncentive)}` + )}
@@ -153,6 +205,12 @@ const getSectionMarkup = (sectionInfo) => { ${formatCents(sectionInfo.ddp)}
+
+ + + ${formatCents(sectionInfo.sitReimbursement)} + +
); @@ -161,16 +219,102 @@ const getSectionMarkup = (sectionInfo) => { } }; -export default function PPMHeaderSummary({ sectionInfo }) { +export default function HeaderSection({ sectionInfo, dataTestId, updatedItemName, setUpdatedItemName }) { const requestDetailsButtonTestId = `${sectionInfo.type}-showRequestDetailsButton`; + const { shipmentId, moveCode } = useParams(); + const { mtoShipment, refetchMTOShipment, isFetching: isFetchingMtoShipment } = usePPMShipmentDocsQueries(shipmentId); + const queryClient = useQueryClient(); const [showDetails, setShowDetails] = useState(false); + const [isEditModalVisible, setIsEditModalVisible] = useState(false); + const [itemName, setItemName] = useState(''); + const [sectionType, setSectionType] = useState(''); + const [isSubmitting, setIsSubmitting] = useState(false); + const showRequestDetailsButton = true; const handleToggleDetails = () => setShowDetails((prevState) => !prevState); const showDetailsChevron = showDetails ? 'chevron-up' : 'chevron-down'; const showDetailsText = showDetails ? 'Hide details' : 'Show details'; + const isFetchingCloseout = useIsFetching({ queryKey: [PPMCLOSEOUT, mtoShipment?.ppmShipment?.id] }) > 0; + const isFetchingItems = isFetchingMtoShipment || isFetchingCloseout; + + const handleEditOnClose = () => { + setIsEditModalVisible(false); + setItemName(''); + setSectionType(''); + setIsSubmitting(false); + }; + + useEffect(() => { + if (isEditModalVisible) { + refetchMTOShipment(); + } + }, [isEditModalVisible, refetchMTOShipment]); + + const { mtoShipments } = useEditShipmentQueries(moveCode); + + const { mutate: mutateMTOShipment } = useMutation(updateMTOShipment, { + onSuccess: (updatedMTOShipments) => { + const updatedMTOShipment = updatedMTOShipments.mtoShipments[shipmentId]; + mtoShipments[mtoShipments.findIndex((shipment) => shipment.id === updatedMTOShipment.id)] = updatedMTOShipment; + queryClient.setQueryData([MTO_SHIPMENTS, updatedMTOShipment.moveTaskOrderID, false], mtoShipments); + queryClient.invalidateQueries([MTO_SHIPMENTS, updatedMTOShipment.moveTaskOrderID]); + queryClient.invalidateQueries([PPMCLOSEOUT, updatedMTOShipment?.ppmShipment?.id]); + refetchMTOShipment(); + handleEditOnClose(); + }, + onSettled: () => { + setIsSubmitting(false); + }, + }); + + const handleEditOnClick = (type, name) => { + setIsEditModalVisible(true); + setItemName(name); + setSectionType(type); + setUpdatedItemName(name); + }; + + const handleEditSubmit = (values) => { + if (isSubmitting) return; + + setIsSubmitting(true); + let body = {}; + + switch (itemName) { + case 'actualMoveDate': + body = { actualMoveDate: formatDate(values.actualMoveDate, 'DD MMM YYYY', 'YYYY-MM-DD') }; + break; + case 'advanceAmountReceived': + if (values.advanceAmountReceived === '0') { + body = { + advanceAmountReceived: null, + hasReceivedAdvance: false, + }; + } else { + body = { + advanceAmountReceived: values.advanceAmountReceived * 100, + hasReceivedAdvance: true, + }; + } + break; + + default: + break; + } + + mutateMTOShipment({ + moveTaskOrderID: mtoShipment.moveTaskOrderID, + shipmentID: mtoShipment.id, + ifMatchETag: mtoShipment.eTag, + body: { + ppmShipment: body, + }, + }); + }; + return ( -
+

{getSectionTitle(sectionInfo)}

@@ -187,7 +331,16 @@ export default function PPMHeaderSummary({ sectionInfo }) { )}
- {showDetails && getSectionMarkup(sectionInfo)} + {showDetails && getSectionMarkup(sectionInfo, handleEditOnClick, isFetchingItems, updatedItemName)} + {isEditModalVisible && ( + + )} ); } diff --git a/src/components/Office/PPM/PPMHeaderSummary/HeaderSection.module.scss b/src/components/Office/PPM/PPMHeaderSummary/HeaderSection.module.scss index 57bcd04a06e..8b6c5b7e2fe 100644 --- a/src/components/Office/PPM/PPMHeaderSummary/HeaderSection.module.scss +++ b/src/components/Office/PPM/PPMHeaderSummary/HeaderSection.module.scss @@ -16,6 +16,28 @@ h4 { @include u-margin-y(2.5); } + .edit-btn-wrapper { + display: flex; + width: 100%; + justify-content: flex-end; + } + .edit-btn { + margin: 0; + padding: 0 0 0 3px; + display: inline; + color: $primary; + background-color: transparent; + height: auto; + + &:hover, + &:focus { + color: $primary; + background-color: transparent; + } + } + .edit-btn:disabled { + cursor: not-allowed; + } } .Details { @@ -23,9 +45,7 @@ @include u-padding-x(1.5); div { - display: grid; - grid-template-columns: 300px 200px; - align-items: center; + display: block; @include u-margin-y(1); span { diff --git a/src/components/Office/PPM/PPMHeaderSummary/HeaderSection.test.jsx b/src/components/Office/PPM/PPMHeaderSummary/HeaderSection.test.jsx index 0ce4c6b5100..e1d5ae3f93b 100644 --- a/src/components/Office/PPM/PPMHeaderSummary/HeaderSection.test.jsx +++ b/src/components/Office/PPM/PPMHeaderSummary/HeaderSection.test.jsx @@ -1,19 +1,141 @@ import React from 'react'; -import { render, waitFor, screen, fireEvent } from '@testing-library/react'; +import { waitFor, screen, fireEvent, act } from '@testing-library/react'; import HeaderSection from './HeaderSection'; +import { useEditShipmentQueries, usePPMShipmentDocsQueries } from 'hooks/queries'; +import { renderWithProviders } from 'testUtils'; + beforeEach(() => { jest.clearAllMocks(); }); +const routingParams = { moveCode: 'move123', shipmentId: 'shipment123' }; +const mockRoutingConfig = { + params: routingParams, +}; + +jest.mock('hooks/queries', () => ({ + usePPMShipmentDocsQueries: jest.fn(), + useEditShipmentQueries: jest.fn(), +})); + +const useEditShipmentQueriesReturnValue = { + move: { + id: '9c7b255c-2981-4bf8-839f-61c7458e2b4d', + ordersId: '1', + status: 'NEEDS SERVICE COUNSELING', + }, + order: { + id: '1', + originDutyLocation: { + address: { + streetAddress1: '', + city: 'Fort Knox', + state: 'KY', + postalCode: '40121', + }, + }, + destinationDutyLocation: { + address: { + streetAddress1: '', + city: 'Fort Irwin', + state: 'CA', + postalCode: '92310', + }, + }, + customer: { + agency: 'ARMY', + backup_contact: { + email: 'email@example.com', + name: 'name', + phone: '555-555-5555', + }, + current_address: { + city: 'Beverly Hills', + country: 'US', + eTag: 'MjAyMS0wMS0yMVQxNTo0MTozNS41Mzg0Njha', + id: '3a5f7cf2-6193-4eb3-a244-14d21ca05d7b', + postalCode: '90210', + state: 'CA', + streetAddress1: '123 Any Street', + streetAddress2: 'P.O. Box 12345', + streetAddress3: 'c/o Some Person', + }, + dodID: '6833908165', + eTag: 'MjAyMS0wMS0yMVQxNTo0MTozNS41NjAzNTJa', + email: 'combo@ppm.hhg', + first_name: 'Submitted', + id: 'f6bd793f-7042-4523-aa30-34946e7339c9', + last_name: 'Ppmhhg', + phone: '555-555-5555', + }, + entitlement: { + authorizedWeight: 8000, + dependentsAuthorized: true, + eTag: 'MjAyMS0wMS0yMVQxNTo0MTozNS41NzgwMzda', + id: 'e0fefe58-0710-40db-917b-5b96567bc2a8', + nonTemporaryStorage: true, + privatelyOwnedVehicle: true, + proGearWeight: 2000, + proGearWeightSpouse: 500, + storageInTransit: 2, + totalDependents: 1, + totalWeight: 8000, + }, + order_number: 'ORDER3', + order_type: 'PERMANENT_CHANGE_OF_STATION', + order_type_detail: 'HHG_PERMITTED', + tac: '9999', + }, + mtoShipments: [ + { + customerRemarks: 'please treat gently', + destinationAddress: { + city: 'Fairfield', + country: 'US', + id: '672ff379-f6e3-48b4-a87d-796713f8f997', + postalCode: '94535', + state: 'CA', + streetAddress1: '987 Any Avenue', + streetAddress2: 'P.O. Box 9876', + streetAddress3: 'c/o Some Person', + }, + eTag: 'MjAyMC0wNi0xMFQxNTo1ODowMi40MDQwMzFa', + id: 'shipment123', + moveTaskOrderID: '9c7b255c-2981-4bf8-839f-61c7458e2b4d', + pickupAddress: { + city: 'Beverly Hills', + country: 'US', + eTag: 'MjAyMC0wNi0xMFQxNTo1ODowMi4zODQ3Njla', + id: '1686751b-ab36-43cf-b3c9-c0f467d13c19', + postalCode: '90210', + state: 'CA', + streetAddress1: '123 Any Street', + streetAddress2: 'P.O. Box 12345', + streetAddress3: 'c/o Some Person', + }, + requestedPickupDate: '2018-03-15', + scheduledPickupDate: '2018-03-16', + requestedDeliveryDate: '2018-04-15', + scheduledDeliveryDate: '2014-04-16', + shipmentType: 'HHG', + status: 'SUBMITTED', + updatedAt: '2020-06-10T15:58:02.404031Z', + }, + ], + isLoading: false, + isError: false, + isSuccess: true, +}; + const shipmentInfoProps = { sectionInfo: { type: 'shipmentInfo', plannedMoveDate: '2020-03-15', actualMoveDate: '2022-01-12', - actualPickupPostalCode: '42444', - actualDestinationPostalCode: '30813', + pickupAddress: '812 S 129th St, #123, San Antonio, TX 78234', + destinationAddress: '456 Oak Ln., #123, Oakland, CA 94611', miles: 513, estimatedWeight: 4000, actualWeight: 4200, @@ -43,6 +165,7 @@ const incentiveFactorsProps = { unpackPrice: 10000, dop: 15640, ddp: 34640, + sitReimbursement: 30000, }, }; @@ -56,6 +179,7 @@ const incentiveFactorsShorthaulProps = { unpackPrice: 10000, dop: 15640, ddp: 34640, + sitReimbursement: 30000, }, }; @@ -66,7 +190,9 @@ const invalidSectionTypeProps = { }; const clickDetailsButton = async (buttonType) => { - fireEvent.click(screen.getByTestId(`${buttonType}-showRequestDetailsButton`)); + await act(async () => { + await fireEvent.click(screen.getByTestId(`${buttonType}-showRequestDetailsButton`)); + }); await waitFor(() => { expect(screen.getByText('Hide Details', { exact: false })).toBeInTheDocument(); }); @@ -75,22 +201,27 @@ const clickDetailsButton = async (buttonType) => { describe('PPMHeaderSummary component', () => { describe('displays Shipment Info section', () => { it('renders Shipment Info section on load with defaults', async () => { - render(); + usePPMShipmentDocsQueries.mockReturnValue(useEditShipmentQueriesReturnValue); + useEditShipmentQueries.mockReturnValue(useEditShipmentQueriesReturnValue); + await act(async () => { + renderWithProviders(, mockRoutingConfig); + }); await waitFor(() => { expect(screen.getByRole('heading', { level: 4, name: 'Shipment Info' })).toBeInTheDocument(); }); - - clickDetailsButton('shipmentInfo'); + await act(async () => { + clickDetailsButton('shipmentInfo'); + }); expect(screen.getByText('Planned Move Start Date')).toBeInTheDocument(); expect(screen.getByText('15-Mar-2020')).toBeInTheDocument(); expect(screen.getByText('Actual Move Start Date')).toBeInTheDocument(); expect(screen.getByText('12-Jan-2022')).toBeInTheDocument(); - expect(screen.getByText('Starting ZIP')).toBeInTheDocument(); - expect(screen.getByText('42444')).toBeInTheDocument(); - expect(screen.getByText('Ending ZIP')).toBeInTheDocument(); - expect(screen.getByText('30813')).toBeInTheDocument(); + expect(screen.getByText('Starting Address')).toBeInTheDocument(); + expect(screen.getByText('812 S 129th St, #123, San Antonio, TX 78234')).toBeInTheDocument(); + expect(screen.getByText('Ending Address')).toBeInTheDocument(); + expect(screen.getByText('456 Oak Ln., #123, Oakland, CA 94611')).toBeInTheDocument(); expect(screen.getByText('Miles')).toBeInTheDocument(); expect(screen.getByText('513')).toBeInTheDocument(); expect(screen.getByText('Estimated Net Weight')).toBeInTheDocument(); @@ -102,9 +233,14 @@ describe('PPMHeaderSummary component', () => { describe('displays "Incentives/Costs" section', () => { it('renders "Incentives/Costs" section on load with correct prop values', async () => { - render(); - - clickDetailsButton('incentives'); + usePPMShipmentDocsQueries.mockReturnValue(useEditShipmentQueriesReturnValue); + useEditShipmentQueries.mockReturnValue(useEditShipmentQueriesReturnValue); + await act(async () => { + renderWithProviders(, mockRoutingConfig); + }); + await act(async () => { + clickDetailsButton('incentives'); + }); expect(screen.getByText('Government Constructed Cost (GCC)')).toBeInTheDocument(); expect(screen.getByTestId('gcc')).toHaveTextContent('$72,312.85'); @@ -121,9 +257,14 @@ describe('PPMHeaderSummary component', () => { describe('displays "Incentive Factors" section', () => { it('renders "Incentive Factors" on load with correct prop values', async () => { - render(); - - clickDetailsButton('incentiveFactors'); + usePPMShipmentDocsQueries.mockReturnValue(useEditShipmentQueriesReturnValue); + useEditShipmentQueries.mockReturnValue(useEditShipmentQueriesReturnValue); + await act(async () => { + renderWithProviders(, mockRoutingConfig); + }); + await act(async () => { + clickDetailsButton('incentiveFactors'); + }); expect(screen.getByText('Linehaul Price')).toBeInTheDocument(); expect(screen.getByTestId('haulPrice')).toHaveTextContent('$68,926.68'); @@ -137,12 +278,18 @@ describe('PPMHeaderSummary component', () => { expect(screen.getByTestId('originPrice')).toHaveTextContent('$156.40'); expect(screen.getByText('Destination Price')).toBeInTheDocument(); expect(screen.getByTestId('destinationPrice')).toHaveTextContent('$346.40'); + expect(screen.getByTestId('sitReimbursement')).toHaveTextContent('$300.00'); }); it('renders "Shorthaul" in place of linehaul when given a shorthaul type', async () => { - render(); - - clickDetailsButton('incentiveFactors'); + usePPMShipmentDocsQueries.mockReturnValue(useEditShipmentQueriesReturnValue); + useEditShipmentQueries.mockReturnValue(useEditShipmentQueriesReturnValue); + await act(async () => { + renderWithProviders(, mockRoutingConfig); + }); + await act(async () => { + clickDetailsButton('incentiveFactors'); + }); expect(screen.getByText('Shorthaul Price')).toBeInTheDocument(); expect(screen.getByTestId('haulPrice')).toHaveTextContent('$68,926.68'); @@ -156,12 +303,17 @@ describe('PPMHeaderSummary component', () => { expect(screen.getByTestId('originPrice')).toHaveTextContent('$156.40'); expect(screen.getByText('Destination Price')).toBeInTheDocument(); expect(screen.getByTestId('destinationPrice')).toHaveTextContent('$346.40'); + expect(screen.getByTestId('sitReimbursement')).toHaveTextContent('$300.00'); }); }); describe('handles errors correctly', () => { it('renders an alert if an unknown section type was passed in', async () => { - render(); + usePPMShipmentDocsQueries.mockReturnValue(useEditShipmentQueriesReturnValue); + useEditShipmentQueries.mockReturnValue(useEditShipmentQueriesReturnValue); + await act(async () => { + renderWithProviders(, mockRoutingConfig); + }); const alert = screen.getByTestId('alert'); expect(alert).toBeInTheDocument(); @@ -169,10 +321,15 @@ describe('PPMHeaderSummary component', () => { }); it('renders an alert if an unknown section type was passed in and details are expanded', async () => { - render(); - - clickDetailsButton(invalidSectionTypeProps.sectionInfo.type); - expect(screen.findByText('An error occured while getting section markup!')); + usePPMShipmentDocsQueries.mockReturnValue(useEditShipmentQueriesReturnValue); + useEditShipmentQueries.mockReturnValue(useEditShipmentQueriesReturnValue); + await act(async () => { + renderWithProviders(, mockRoutingConfig); + }); + await act(async () => { + clickDetailsButton(invalidSectionTypeProps.sectionInfo.type); + }); + expect(screen.getByText('An error occured while getting section markup!')).toBeInTheDocument(); }); }); }); diff --git a/src/components/Office/PPM/PPMHeaderSummary/PPMHeaderSummary.jsx b/src/components/Office/PPM/PPMHeaderSummary/PPMHeaderSummary.jsx index 6c41616c6ac..bbc5af1c0d6 100644 --- a/src/components/Office/PPM/PPMHeaderSummary/PPMHeaderSummary.jsx +++ b/src/components/Office/PPM/PPMHeaderSummary/PPMHeaderSummary.jsx @@ -1,4 +1,4 @@ -import { React } from 'react'; +import React, { useState } from 'react'; import { number, bool } from 'prop-types'; import classnames from 'classnames'; @@ -8,8 +8,9 @@ import styles from './PPMHeaderSummary.module.scss'; import LoadingPlaceholder from 'shared/LoadingPlaceholder'; import SomethingWentWrong from 'shared/SomethingWentWrong'; import { usePPMCloseoutQuery } from 'hooks/queries'; +import { formatCustomerContactFullAddress } from 'utils/formatters'; -const GCCAndIncentiveInfo = ({ ppmShipmentInfo }) => { +const GCCAndIncentiveInfo = ({ ppmShipmentInfo, updatedItemName, setUpdatedItemName }) => { const { ppmCloseout, isLoading, isError } = usePPMCloseoutQuery(ppmShipmentInfo.id); if (isLoading) return ; @@ -19,9 +20,9 @@ const GCCAndIncentiveInfo = ({ ppmShipmentInfo }) => { isAdvanceReceived: ppmShipmentInfo.hasReceivedAdvance, advanceAmountRequested: ppmShipmentInfo.advanceAmountRequested, advanceAmountReceived: ppmShipmentInfo.advanceAmountReceived, - grossIncentive: ppmCloseout.grossIncentive, - gcc: ppmCloseout.gcc, - remainingIncentive: ppmCloseout.remainingIncentive, + grossIncentive: ppmCloseout.grossIncentive + ppmCloseout.SITReimbursement, + gcc: ppmCloseout.gcc + ppmCloseout.SITReimbursement, + remainingIncentive: ppmCloseout.remainingIncentive + ppmCloseout.SITReimbursement, }; const incentiveFactors = { @@ -32,27 +33,43 @@ const GCCAndIncentiveInfo = ({ ppmShipmentInfo }) => { unpackPrice: ppmCloseout.unpackPrice, dop: ppmCloseout.dop, ddp: ppmCloseout.ddp, + sitReimbursement: ppmCloseout.SITReimbursement, }; return ( <> +

- + ); }; export default function PPMHeaderSummary({ ppmShipmentInfo, ppmNumber, showAllFields }) { + const [updatedItemName, setUpdatedItemName] = useState(''); + const shipmentInfo = { plannedMoveDate: ppmShipmentInfo.expectedDepartureDate, actualMoveDate: ppmShipmentInfo.actualMoveDate, - actualPickupPostalCode: ppmShipmentInfo.actualPickupPostalCode, - actualDestinationPostalCode: ppmShipmentInfo.actualDestinationPostalCode, + pickupAddress: ppmShipmentInfo.pickupAddress + ? formatCustomerContactFullAddress(ppmShipmentInfo.pickupAddress) + : '—', + destinationAddress: ppmShipmentInfo.destinationAddress + ? formatCustomerContactFullAddress(ppmShipmentInfo.destinationAddress) + : '—', miles: ppmShipmentInfo.miles, estimatedWeight: ppmShipmentInfo.estimatedWeight, actualWeight: ppmShipmentInfo.actualWeight, @@ -66,12 +83,21 @@ export default function PPMHeaderSummary({ ppmShipmentInfo, ppmNumber, showAllFi -
- {showAllFields && } + {showAllFields && ( + + )} ); diff --git a/src/components/Office/PPM/PPMHeaderSummary/PPMHeaderSummary.module.scss b/src/components/Office/PPM/PPMHeaderSummary/PPMHeaderSummary.module.scss index 213fb941082..4d99d82e031 100644 --- a/src/components/Office/PPM/PPMHeaderSummary/PPMHeaderSummary.module.scss +++ b/src/components/Office/PPM/PPMHeaderSummary/PPMHeaderSummary.module.scss @@ -2,6 +2,8 @@ @import 'shared/styles/colors'; .PPMHeaderSummary { + padding: 0 !important; + .header { :global(.usa-label) { width: auto; diff --git a/src/components/Office/PPM/PPMHeaderSummary/PPMHeaderSummary.test.jsx b/src/components/Office/PPM/PPMHeaderSummary/PPMHeaderSummary.test.jsx index 6822140dcd1..eff4f7d21ea 100644 --- a/src/components/Office/PPM/PPMHeaderSummary/PPMHeaderSummary.test.jsx +++ b/src/components/Office/PPM/PPMHeaderSummary/PPMHeaderSummary.test.jsx @@ -1,19 +1,160 @@ import React from 'react'; -import { render, waitFor, screen, fireEvent } from '@testing-library/react'; +import { waitFor, screen, fireEvent } from '@testing-library/react'; import PPMHeaderSummary from './PPMHeaderSummary'; +import { useEditShipmentQueries, usePPMShipmentDocsQueries } from 'hooks/queries'; +import { renderWithProviders } from 'testUtils'; +import { tooRoutes } from 'constants/routes'; + beforeEach(() => { jest.clearAllMocks(); }); +const mockNavigate = jest.fn(); +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useNavigate: () => mockNavigate, +})); +const routingParams = { moveCode: 'move123', shipmentId: 'shipment123' }; +const mockRoutingConfig = { + path: tooRoutes.BASE_SHIPMENT_EDIT_PATH, + params: routingParams, +}; + +jest.mock('hooks/queries', () => ({ + usePPMShipmentDocsQueries: jest.fn(), + useEditShipmentQueries: jest.fn(), +})); + +const useEditShipmentQueriesReturnValue = { + move: { + id: '9c7b255c-2981-4bf8-839f-61c7458e2b4d', + ordersId: '1', + status: 'NEEDS SERVICE COUNSELING', + }, + order: { + id: '1', + originDutyLocation: { + address: { + streetAddress1: '', + city: 'Fort Knox', + state: 'KY', + postalCode: '40121', + }, + }, + destinationDutyLocation: { + address: { + streetAddress1: '', + city: 'Fort Irwin', + state: 'CA', + postalCode: '92310', + }, + }, + customer: { + agency: 'ARMY', + backup_contact: { + email: 'email@example.com', + name: 'name', + phone: '555-555-5555', + }, + current_address: { + city: 'Beverly Hills', + country: 'US', + eTag: 'MjAyMS0wMS0yMVQxNTo0MTozNS41Mzg0Njha', + id: '3a5f7cf2-6193-4eb3-a244-14d21ca05d7b', + postalCode: '90210', + state: 'CA', + streetAddress1: '123 Any Street', + streetAddress2: 'P.O. Box 12345', + streetAddress3: 'c/o Some Person', + }, + dodID: '6833908165', + eTag: 'MjAyMS0wMS0yMVQxNTo0MTozNS41NjAzNTJa', + email: 'combo@ppm.hhg', + first_name: 'Submitted', + id: 'f6bd793f-7042-4523-aa30-34946e7339c9', + last_name: 'Ppmhhg', + phone: '555-555-5555', + }, + entitlement: { + authorizedWeight: 8000, + dependentsAuthorized: true, + eTag: 'MjAyMS0wMS0yMVQxNTo0MTozNS41NzgwMzda', + id: 'e0fefe58-0710-40db-917b-5b96567bc2a8', + nonTemporaryStorage: true, + privatelyOwnedVehicle: true, + proGearWeight: 2000, + proGearWeightSpouse: 500, + storageInTransit: 2, + totalDependents: 1, + totalWeight: 8000, + }, + order_number: 'ORDER3', + order_type: 'PERMANENT_CHANGE_OF_STATION', + order_type_detail: 'HHG_PERMITTED', + tac: '9999', + }, + mtoShipments: [ + { + customerRemarks: 'please treat gently', + destinationAddress: { + city: 'Fairfield', + country: 'US', + id: '672ff379-f6e3-48b4-a87d-796713f8f997', + postalCode: '94535', + state: 'CA', + streetAddress1: '987 Any Avenue', + streetAddress2: 'P.O. Box 9876', + streetAddress3: 'c/o Some Person', + }, + eTag: 'MjAyMC0wNi0xMFQxNTo1ODowMi40MDQwMzFa', + id: 'shipment123', + moveTaskOrderID: '9c7b255c-2981-4bf8-839f-61c7458e2b4d', + pickupAddress: { + city: 'Beverly Hills', + country: 'US', + eTag: 'MjAyMC0wNi0xMFQxNTo1ODowMi4zODQ3Njla', + id: '1686751b-ab36-43cf-b3c9-c0f467d13c19', + postalCode: '90210', + state: 'CA', + streetAddress1: '123 Any Street', + streetAddress2: 'P.O. Box 12345', + streetAddress3: 'c/o Some Person', + }, + requestedPickupDate: '2018-03-15', + scheduledPickupDate: '2018-03-16', + requestedDeliveryDate: '2018-04-15', + scheduledDeliveryDate: '2014-04-16', + shipmentType: 'HHG', + status: 'SUBMITTED', + updatedAt: '2020-06-10T15:58:02.404031Z', + }, + ], + isLoading: false, + isError: false, + isSuccess: true, +}; + const defaultProps = { ppmShipmentInfo: { id: '32ecb311-edbe-4fd4-96ee-bd693113f3f3', expectedDepartureDate: '2022-12-02', actualMoveDate: '2022-12-06', - actualPickupPostalCode: '90210', - actualDestinationPostalCode: '94611', + pickupAddress: { + streetAddress1: '812 S 129th St', + streetAddress2: '#123', + city: 'San Antonio', + state: 'TX', + postalCode: '78234', + }, + destinationAddress: { + streetAddress1: '456 Oak Ln.', + streetAddress2: '#123', + city: 'Oakland', + state: 'CA', + postalCode: '94611', + }, miles: 300, estimatedWeight: 3000, actualWeight: 3500, @@ -25,7 +166,9 @@ const defaultProps = { describe('PPMHeaderSummary component', () => { describe('displays form', () => { it('renders blank form on load with defaults', async () => { - render(); + usePPMShipmentDocsQueries.mockReturnValue(useEditShipmentQueriesReturnValue); + useEditShipmentQueries.mockReturnValue(useEditShipmentQueriesReturnValue); + renderWithProviders(, mockRoutingConfig); await waitFor(() => { expect(screen.getByRole('heading', { level: 3, name: 'PPM 1' })).toBeInTheDocument(); @@ -39,10 +182,10 @@ describe('PPMHeaderSummary component', () => { expect(screen.getByText('02-Dec-2022')).toBeInTheDocument(); expect(screen.getByText('Actual Move Start Date')).toBeInTheDocument(); expect(screen.getByText('06-Dec-2022')).toBeInTheDocument(); - expect(screen.getByText('Starting ZIP')).toBeInTheDocument(); - expect(screen.getByText('90210')).toBeInTheDocument(); - expect(screen.getByText('Ending ZIP')).toBeInTheDocument(); - expect(screen.getByText('94611')).toBeInTheDocument(); + expect(screen.getByText('Starting Address')).toBeInTheDocument(); + expect(screen.getByText('812 S 129th St, #123, San Antonio, TX 78234')).toBeInTheDocument(); + expect(screen.getByText('Ending Address')).toBeInTheDocument(); + expect(screen.getByText('456 Oak Ln., #123, Oakland, CA 94611')).toBeInTheDocument(); expect(screen.getByText('Miles')).toBeInTheDocument(); expect(screen.getByText('300')).toBeInTheDocument(); expect(screen.getByText('Estimated Net Weight')).toBeInTheDocument(); diff --git a/src/components/Office/PPM/ReviewDocumentsSidePanel/ReviewDocumentsSidePanel.jsx b/src/components/Office/PPM/ReviewDocumentsSidePanel/ReviewDocumentsSidePanel.jsx index 66c707a9ee2..c50c5c71dd8 100644 --- a/src/components/Office/PPM/ReviewDocumentsSidePanel/ReviewDocumentsSidePanel.jsx +++ b/src/components/Office/PPM/ReviewDocumentsSidePanel/ReviewDocumentsSidePanel.jsx @@ -95,8 +95,10 @@ export default function ReviewDocumentsSidePanel({ return (
-
+
+
+

Send to customer?

@@ -174,7 +176,7 @@ export default function ReviewDocumentsSidePanel({ : null} {expenseTickets.length > 0 ? expenseSetProjection(expenseTickets).map((exp) => { - if (exp.movingExpenseType !== expenseTypes.STORAGE && exp.status === PPMDocumentsStatus.APPROVED) { + if (exp.status === PPMDocumentsStatus.APPROVED) { total += exp.amount; } return ( diff --git a/src/components/Office/PPM/ReviewDocumentsSidePanel/ReviewDocumentsSidePanel.module.scss b/src/components/Office/PPM/ReviewDocumentsSidePanel/ReviewDocumentsSidePanel.module.scss index fc6e903f49e..069561c21ef 100644 --- a/src/components/Office/PPM/ReviewDocumentsSidePanel/ReviewDocumentsSidePanel.module.scss +++ b/src/components/Office/PPM/ReviewDocumentsSidePanel/ReviewDocumentsSidePanel.module.scss @@ -33,7 +33,8 @@ } header { - @include u-padding(1); + @include u-padding-right(1); + @include u-padding-bottom(1); } hr { @@ -43,7 +44,7 @@ h3 { &:nth-of-type(1) { - @include u-margin-top(0); + @include u-margin-top(1); @include u-margin-bottom(1); } @@ -72,6 +73,12 @@ } } + .HeaderSection { + h4 { + @include u-padding(1); + } + } + .row { display: flex; flex-direction: row; @@ -128,4 +135,8 @@ .sidebar { @include u-margin-top(0); @include u-margin-bottom(0); +} + +.PPMHeaderSummary { + @include u-padding(2); } \ No newline at end of file diff --git a/src/components/Office/PPM/ReviewExpense/ReviewExpense.jsx b/src/components/Office/PPM/ReviewExpense/ReviewExpense.jsx index abc1ffa37b3..7bebd606e70 100644 --- a/src/components/Office/PPM/ReviewExpense/ReviewExpense.jsx +++ b/src/components/Office/PPM/ReviewExpense/ReviewExpense.jsx @@ -166,146 +166,150 @@ export default function ReviewExpense({ : '##'; return ( - - -
-

{`Receipt ${tripNumber}`}

-
- + <> +
+
- - - - {llvmExpenseTypes[selectedExpenseType] === expenseTypes.STORAGE && ( - <> - - - Total days in SIT -
- {daysInSIT} -
- - )} -

{`Review ${allCase( - selectedExpenseType, - )} #${currentCategoryIndex}`}

-

Add a review for this {allCase(selectedExpenseType)}

- {errors.status} -
-
- + +
+

{`Receipt ${tripNumber}`}

+
+
-
{ + setSelectedExpenseType(e.target.value); + setSamePage(true); + const count = computeCurrentCategoryIndex(e.target.value); + setCurrentCategoryIndex(count + 1); + }} > - + {ppmExpenseTypes.map((x) => ( + + ))} + + + + {llvmExpenseTypes[selectedExpenseType] === expenseTypes.STORAGE && ( + <> + + + Total days in SIT +
+ {daysInSIT} +
+ + )} +

{`Review ${allCase( + selectedExpenseType, + )} #${currentCategoryIndex}`}

+

Add a review for this {allCase(selectedExpenseType)}

+ {errors.status} +
+
+ +
+
+ - {values.status === ppmDocumentStatus.EXCLUDED && ( - - - {errors.reason} -