diff --git a/migrations/app/migrations_manifest.txt b/migrations/app/migrations_manifest.txt index 8b547c35245..8613ca2bcf5 100644 --- a/migrations/app/migrations_manifest.txt +++ b/migrations/app/migrations_manifest.txt @@ -1059,6 +1059,7 @@ 20241216190428_update_get_zip_code_function_and_update_pricing_proc.up.sql 20241217163231_update_duty_locations_bad_zips.up.sql 20241217180136_add_AK_zips_to_zip3_distances.up.sql +20241217191012_update_move_to_gbloc_for_ak.up.sql 20241218201833_add_PPPO_BASE_ELIZABETH.up.sql 20241218204620_add_international_nts_service_items.up.sql 20241220171035_add_additional_AK_zips_to_zip3_distances.up.sql @@ -1071,6 +1072,8 @@ 20241230190638_remove_AK_zips_from_zip3.up.sql 20241230190647_add_missing_AK_zips_to_zip3_distances.up.sql 20241231155337_add_payment_params_for_international_shuttle.up.sql +20250103130619_revert_data_change_for_gbloc_for_ak.up.sql +20250103142533_update_postal_codes_and_gblocs_for_ak.up.sql 20250103180420_update_pricing_proc_to_use_local_price_variable.up.sql 20250110001339_update_nts_release_enum_name.up.sql 20250110153428_add_shipment_address_updates_to_move_history.up.sql @@ -1081,3 +1084,4 @@ 20250116200912_disable_homesafe_stg_cert.up.sql 20250120144247_update_pricing_proc_to_use_110_percent_weight.up.sql 20250121153007_update_pricing_proc_to_handle_international_shuttle.up.sql +20250123173216_add_destination_queue_db_func_and_gbloc_view.up.sql diff --git a/migrations/app/schema/20241217191012_update_move_to_gbloc_for_ak.up.sql b/migrations/app/schema/20241217191012_update_move_to_gbloc_for_ak.up.sql new file mode 100644 index 00000000000..282ad1b0b16 --- /dev/null +++ b/migrations/app/schema/20241217191012_update_move_to_gbloc_for_ak.up.sql @@ -0,0 +1,43 @@ +delete from postal_code_to_gblocs where postal_code in ( +select uspr_zip_id from v_locations where state = 'AK'); + +drop view move_to_gbloc; +CREATE OR REPLACE VIEW move_to_gbloc AS +SELECT move_id, gbloc FROM ( + SELECT DISTINCT ON (sh.move_id) sh.move_id, s.affiliation, + COALESCE(pctg.gbloc, coalesce(pctg_oconus_bos.gbloc, coalesce(pctg_oconus.gbloc, pctg_ppm.gbloc))) AS gbloc + FROM mto_shipments sh + JOIN moves m ON sh.move_id = m.id + JOIN orders o on m.orders_id = o.id + JOIN service_members s on o.service_member_id = s.id + LEFT JOIN ( SELECT a.id AS address_id, + pctg_1.gbloc, pctg_1.postal_code + FROM addresses a + JOIN postal_code_to_gblocs pctg_1 ON a.postal_code::text = pctg_1.postal_code::text) pctg ON pctg.address_id = sh.pickup_address_id + LEFT JOIN ( SELECT ppm.shipment_id, + pctg_1.gbloc + FROM ppm_shipments ppm + JOIN addresses ppm_address ON ppm.pickup_postal_address_id = ppm_address.id + JOIN postal_code_to_gblocs pctg_1 ON ppm_address.postal_code::text = pctg_1.postal_code::text) pctg_ppm ON pctg_ppm.shipment_id = sh.id + LEFT JOIN ( SELECT a.id AS address_id, + cast(jr.code as varchar) AS gbloc, ga.department_indicator + FROM addresses a + JOIN re_oconus_rate_areas ora ON a.us_post_region_cities_id = ora.us_post_region_cities_id + JOIN gbloc_aors ga ON ora.id = ga.oconus_rate_area_id + JOIN jppso_regions jr ON ga.jppso_regions_id = jr.id + ) pctg_oconus_bos ON pctg_oconus_bos.address_id = sh.pickup_address_id + and case when s.affiliation = 'AIR_FORCE' THEN 'AIR_AND_SPACE_FORCE' + when s.affiliation = 'SPACE_FORCE' THEN 'AIR_AND_SPACE_FORCE' + when s.affiliation = 'NAVY' THEN 'NAVY_AND_MARINES' + when s.affiliation = 'MARINES' THEN 'NAVY_AND_MARINES' + else s.affiliation + end = pctg_oconus_bos.department_indicator + LEFT JOIN ( SELECT a.id AS address_id, + cast(pctg_1.code as varchar) AS gbloc, ga.department_indicator + FROM addresses a + JOIN re_oconus_rate_areas ora ON a.us_post_region_cities_id = ora.us_post_region_cities_id + JOIN gbloc_aors ga ON ora.id = ga.oconus_rate_area_id + JOIN jppso_regions pctg_1 ON ga.jppso_regions_id = pctg_1.id + ) pctg_oconus ON pctg_oconus.address_id = sh.pickup_address_id and pctg_oconus.department_indicator is null + WHERE sh.deleted_at IS NULL + ORDER BY sh.move_id, sh.created_at) as m; \ No newline at end of file diff --git a/migrations/app/schema/20250103130619_revert_data_change_for_gbloc_for_ak.up.sql b/migrations/app/schema/20250103130619_revert_data_change_for_gbloc_for_ak.up.sql new file mode 100644 index 00000000000..2ee43e98f43 --- /dev/null +++ b/migrations/app/schema/20250103130619_revert_data_change_for_gbloc_for_ak.up.sql @@ -0,0 +1,840 @@ +drop view move_to_gbloc; +CREATE OR REPLACE VIEW move_to_gbloc AS +SELECT DISTINCT ON (sh.move_id) sh.move_id AS move_id, COALESCE(pctg.gbloc, pctg_ppm.gbloc) AS gbloc +FROM mto_shipments sh + -- try the pickup_address path + LEFT JOIN + ( + SELECT a.id address_id, pctg.gbloc + FROM addresses a + JOIN postal_code_to_gblocs pctg ON a.postal_code = pctg.postal_code + ) pctg ON pctg.address_id = sh.pickup_address_id + -- try the ppm_shipments path + LEFT JOIN + ( + SELECT ppm.shipment_id, pctg.gbloc + FROM ppm_shipments ppm + JOIN addresses ppm_address ON ppm.pickup_postal_address_id = ppm_address.id + JOIN postal_code_to_gblocs pctg ON ppm_address.postal_code = pctg.postal_code + ) pctg_ppm ON pctg_ppm.shipment_id = sh.id +WHERE sh.deleted_at IS NULL +ORDER BY sh.move_id, sh.created_at; + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99501', 'MBFL', now(), now(), 'd8697416-e345-46a8-9767-47b7abbb3c06'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99502', 'MBFL', now(), now(), '0e060122-7cea-4bcd-b636-31c453088a5d'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99503', 'MBFL', now(), now(), '1bc710db-3f4f-4177-9656-a99956a8b06e'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99504', 'MBFL', now(), now(), 'e35c4fd3-b8d7-46f4-a559-ddfc8e0ad4e9'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99505', 'MBFL', now(), now(), 'f2e40ed3-bc7b-428c-9693-3bc1cc1a9c57'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99506', 'MBFL', now(), now(), 'cf3890e6-16df-46a7-aabb-57010b999ee7'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99507', 'MBFL', now(), now(), 'c869c7aa-e0fd-4933-a4e9-09bd6191b25a'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99508', 'MBFL', now(), now(), 'ca8554c3-d21c-4e26-a77f-6e965c7d31c5'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99509', 'MBFL', now(), now(), '54ea9592-d93d-4102-84ce-7a9c57b6aff8'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99510', 'MBFL', now(), now(), 'f8d0e922-ab5d-4871-bd0c-1f7484b13981'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99511', 'MBFL', now(), now(), '7098c10e-edbf-4cf6-82dd-c09dd7a8f226'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99513', 'MBFL', now(), now(), '8f2d3b79-718e-4d96-b5d2-6b0c40487332'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99514', 'MBFL', now(), now(), '8ff6d888-935c-488c-9b62-33b8f4053b4a'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99515', 'MBFL', now(), now(), 'e3927bca-6677-49d7-a622-ee20f386c28c'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99516', 'MBFL', now(), now(), 'fc5ee3c2-d0b6-4e56-9bcd-e802e14dca7e'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99517', 'MBFL', now(), now(), '84c51c78-972a-4714-8218-8169ee541159'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99518', 'MBFL', now(), now(), '7b3e4eed-3584-4036-9da5-9bc6a7163e4e'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99519', 'MBFL', now(), now(), '62b97b86-e8e7-410a-a267-d101ce5f9a3c'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99520', 'MBFL', now(), now(), 'bce10502-90fb-4f28-8489-f5e6d2ac00ab'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99521', 'MBFL', now(), now(), 'b8c51570-d048-41f8-a1fc-58e6b41d367a'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99522', 'MBFL', now(), now(), '6311d142-f02b-4f49-b719-608d78c91489'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99523', 'MBFL', now(), now(), '967028d9-3a7b-4949-b1a4-e94a1aa25a73'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99524', 'MBFL', now(), now(), 'afd3cc8b-2c02-4e63-8fd1-eb81a1a19b5d'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99529', 'MBFL', now(), now(), 'f08e218c-e55e-43fc-bbdf-bc57aaa65726'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99530', 'MBFL', now(), now(), '65eeaf36-e786-43dd-a18c-fb470a4468f9'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99540', 'MBFL', now(), now(), '2380496a-9087-48bc-a0e2-9cd5ac19f470'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99545', 'MBFL', now(), now(), '6df5025e-e730-427a-8c10-ff6d131d0567'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99546', 'MBFL', now(), now(), '02163620-1da6-4509-b8bb-d8b3336e5c2a'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99547', 'MBFL', now(), now(), 'f869b729-88cd-4770-a435-2dfd4b50c330'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99548', 'MBFL', now(), now(), 'db80b48b-25bd-4ef1-8d5a-33d740af6b0e'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99549', 'MBFL', now(), now(), '09983e53-ae83-41b1-b459-e0ab411ea87e'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99550', 'MAPS', now(), now(), '643db073-5e92-43c0-9b42-a8d9cc800623'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99551', 'MBFL', now(), now(), '9bc29931-880b-42df-a758-017d5abee32d'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99552', 'MBFL', now(), now(), 'f6fa0bb7-fd5c-494e-b62c-b7bc509b632f'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99553', 'MBFL', now(), now(), 'abcb2cbf-389d-4830-ae16-037c55b7bc2c'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99554', 'MBFL', now(), now(), '2d4d9111-f59b-4506-935d-b6601275311a'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99555', 'MBFL', now(), now(), '00c2d5ed-2364-490d-86b9-40cbad4679fb'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99556', 'MBFL', now(), now(), 'b5c75c77-59cf-4089-815b-c0d15d9440f0'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99557', 'MBFL', now(), now(), '999e2c9e-04ed-47da-aca1-2b320ed52666'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99558', 'MBFL', now(), now(), 'cdc2383c-9ead-4501-a6cc-b736ea72ecef'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99559', 'MBFL', now(), now(), '2ca0657c-c121-41e4-a741-b563dee6838e'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99561', 'MBFL', now(), now(), '0c8df634-b6e6-457f-93d7-7d64909bc7cb'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99563', 'MBFL', now(), now(), 'e9a0ebee-3ae3-4d66-b18b-cc3ea417887d'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99564', 'MBFL', now(), now(), '77dd08d9-0997-4d16-babd-1ffccc4222d4'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99565', 'MBFL', now(), now(), '59b6a797-b2e8-4bd7-affc-a5639308a9b3'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99566', 'MBFL', now(), now(), 'cf5b630e-964a-4389-9fa2-e1ed0e6a3041'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99567', 'MBFL', now(), now(), 'f71a916b-e55f-4230-869e-038c319037ce'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99568', 'MBFL', now(), now(), '9719d0c5-1bd0-42fe-89ab-f4dbddcfa588'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99569', 'MBFL', now(), now(), 'fba4bdcf-7707-4826-bf2a-3e7aaf81f309'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99571', 'MBFL', now(), now(), '75e598ff-6d6c-4a80-80bc-de36bc37a3be'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99572', 'MBFL', now(), now(), 'f7b9b7d5-6730-4e8f-9364-e5b1eb1d2c2b'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99573', 'MBFL', now(), now(), '74dcb198-d7c8-4dbc-81ab-33a16559e100'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99574', 'MAPK', now(), now(), '9b9d03a0-e069-48cd-ae65-a66dbd8a3214'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99575', 'MBFL', now(), now(), 'f6ffb9e8-8976-4288-88cd-d10420d1894e'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99576', 'MBFL', now(), now(), '0883cf7f-c2f9-4865-91c3-34df59486f01'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99577', 'MBFL', now(), now(), 'a5e58cce-5375-498b-bfdb-d2e4b50ee2b7'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99578', 'MBFL', now(), now(), '63113a71-6f32-4531-991b-015d51be0ef7'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99579', 'MBFL', now(), now(), 'be2f7dfb-a020-45b5-afa6-0e3b6fd669bf'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99580', 'MBFL', now(), now(), '29b1f268-8ad5-400c-8aa6-0b4b851f8588'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99581', 'MBFL', now(), now(), '5e1dee94-93f9-4b7d-8445-7de967031bfa'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99583', 'MBFL', now(), now(), '2ab06e55-ae2b-4c19-b679-81ee89d098a5'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99585', 'MBFL', now(), now(), 'd177b210-8362-4073-9862-43333203abfc'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99586', 'MBFL', now(), now(), 'c8bdc299-d65d-4b4b-a0ad-0ef6c8ca905d'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99587', 'MBFL', now(), now(), '9543c328-16d2-484b-9e62-1965a63f1d2e'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99588', 'MBFL', now(), now(), '08d82a7f-8417-407d-b352-9e0f3ef9e9cd'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99589', 'MBFL', now(), now(), 'e09e4805-d0a9-4347-8f63-7e221c4b6d7e'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99590', 'MBFL', now(), now(), '3022675c-9e50-403e-987c-7e79762274c2'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99591', 'MBFL', now(), now(), '57eebbd9-4b15-4b6f-923a-1d1db65d72bc'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99599', 'MBFL', now(), now(), '78a46448-b22a-4da0-a42a-07af993848bc'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99602', 'MBFL', now(), now(), '101c94fc-11cf-4317-a63b-c3c903d1f9b3'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99603', 'MBFL', now(), now(), '67ebaf88-8131-4215-b6a4-3b3ecb3862f0'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99604', 'MBFL', now(), now(), '45e5dfdd-9dbc-439a-96ac-292b820aa292'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99605', 'MBFL', now(), now(), 'd403b760-8ad8-409b-b8d4-e0ad9dfd3947'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99606', 'MBFL', now(), now(), 'ac7a083e-3300-4881-874b-6bbd206a4e92'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99607', 'MBFL', now(), now(), 'f8d072a2-099d-4767-9b1d-b5dd48a79a19'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99608', 'MAPS', now(), now(), '889e4f60-6352-443c-8705-734ed91dc7a4'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99609', 'MBFL', now(), now(), 'da00dfc3-a372-4e9f-8ddb-f0d9c792ab36'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99610', 'MBFL', now(), now(), '53b8b7d8-337a-43fe-9a97-e2f5083210aa'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99611', 'MBFL', now(), now(), 'f7211d4f-8ffb-482f-b268-07b9d79c467e'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99612', 'MBFL', now(), now(), 'e7340a1b-3278-42aa-a067-021863d676dd'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99613', 'MBFL', now(), now(), '7de673ca-c91d-4bc1-b450-fdaa0c199723'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99614', 'MBFL', now(), now(), 'fd72416c-c88b-4c0f-a3e0-28fd924fd7d7'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99615', 'MAPS', now(), now(), 'b0597a99-16d7-4e1e-9820-042971b2551f'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99619', 'MAPS', now(), now(), '8d05d190-fda5-4930-838d-76f37892417c'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99620', 'MBFL', now(), now(), 'fc2456f7-d2ca-4cb3-b16b-f50388c09a12'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99621', 'MBFL', now(), now(), 'da74789a-b710-4332-a973-cc8ff104f80f'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99622', 'MBFL', now(), now(), '52b0c551-7d40-496b-9e5a-3aeb7e68f415'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99623', 'MBFL', now(), now(), '4613c99b-da96-4649-8de5-8e445af78f99'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99624', 'MAPS', now(), now(), '13e0d2ba-852e-4970-b60c-464740975141'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99625', 'MBFL', now(), now(), '772070b7-2029-40cf-82b7-e8b839f2740f'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99626', 'MBFL', now(), now(), 'a6a4b405-e1af-455f-89d5-088de0afebfa'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99627', 'MBFL', now(), now(), 'e0778102-5fb8-4366-bbd2-413a96946a6d'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99628', 'MBFL', now(), now(), '4dad6942-608b-415b-86b1-4575cbe92b14'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99629', 'MBFL', now(), now(), '534a58f3-e96b-41cd-86f5-d3c3f7553063'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99630', 'MBFL', now(), now(), 'aca18cb8-d348-4dfa-bfce-3508ed050ce2'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99631', 'MBFL', now(), now(), '90fd8694-e43b-49f7-a22b-27f95170069c'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99632', 'MBFL', now(), now(), 'b6736f3e-b561-4658-a22a-822b4d141db6'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99633', 'MBFL', now(), now(), 'e622bb3a-8c83-4230-b953-a256a7ed2b50'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99634', 'MBFL', now(), now(), 'a042efbf-24da-489f-ab6d-15179847cec1'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99635', 'MBFL', now(), now(), '153a77b9-ae9f-4e3c-8b7e-35631300491d'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99636', 'MBFL', now(), now(), '988b8373-ca1d-459f-a0cc-598c20ad1e07'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99637', 'MBFL', now(), now(), 'eb47a507-5f66-4344-bed9-d165d8275fa9'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99638', 'MBFL', now(), now(), '0858bd59-a16b-47ca-9cb8-670411737d4d'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99639', 'MBFL', now(), now(), '52b0ac8b-3931-47d1-aa66-2283a9a1650a'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99640', 'MBFL', now(), now(), '9040a7e0-de08-494b-8d69-27cd4a53bc90'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99641', 'MBFL', now(), now(), '6e1d8641-0448-40cc-88e3-67d4f8466a8e'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99643', 'MAPS', now(), now(), '15c1aea9-9b9b-4f6e-93cf-a114ac9175f8'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99644', 'MAPS', now(), now(), '6f294618-1e61-42fc-8d6b-cd870b0b08fc'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99645', 'MBFL', now(), now(), '82d2557f-263b-4108-a75b-ff745aea08f0'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99647', 'MBFL', now(), now(), 'c432e858-d177-4faa-8d0b-97c5305b61e7'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99648', 'MBFL', now(), now(), '273ecc7f-0b37-439e-97e6-86a2f7ea7114'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99649', 'MBFL', now(), now(), '213d21e6-0b04-4f5c-90f8-4ddc9938381d'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99650', 'MBFL', now(), now(), 'f2a5f071-205f-4cc1-9448-44058d9af3f5'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99651', 'MBFL', now(), now(), 'c16c38b5-eb50-4dc7-8a40-aa9e7e80bf2f'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99652', 'MBFL', now(), now(), 'ef17b53b-f840-4b2d-9f66-3f80c413b3c1'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99653', 'MBFL', now(), now(), '7307956d-84f3-4c22-ad2f-40b62dc0a0d7'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99654', 'MBFL', now(), now(), '47ccb8d8-8df2-4293-9f86-f5703aea0dba'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99655', 'MBFL', now(), now(), '69d0d1e7-8c8e-4cde-82dc-b8374b8b4861'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99656', 'MBFL', now(), now(), 'e0be218f-2d2f-4bac-b8b5-e09ef3f28742'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99657', 'MBFL', now(), now(), 'bd121ed0-6592-427a-9ba9-c06ab3a703dd'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99658', 'MBFL', now(), now(), '6acfa9fe-137e-4a92-b21c-39e627cc378a'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99659', 'MBFL', now(), now(), 'f131070d-b5d8-453e-bac7-ad436ea124dc'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99660', 'MBFL', now(), now(), 'cab88f64-c8c1-42f1-be62-7b4cce31aeb3'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99661', 'MBFL', now(), now(), 'e5a62394-0278-42a3-84e3-57ff2240dc60'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99662', 'MBFL', now(), now(), '8c0d1e5d-6afe-4552-b7cc-3b5a6fbdc3db'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99663', 'MBFL', now(), now(), '44beec24-6856-43f7-ab55-b48286d2829b'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99664', 'MBFL', now(), now(), 'c35ed3e5-c3a6-43e2-9794-56709f93620f'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99665', 'MBFL', now(), now(), '06b6f8ed-7f4e-4b7a-94b6-def7b619a03d'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99666', 'MBFL', now(), now(), '959c959f-b829-471c-a63e-b3cffa15f6c7'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99667', 'MBFL', now(), now(), '75ef0a3a-cc89-4a3b-809f-6cdb6753bc25'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99668', 'MBFL', now(), now(), 'c2f65e88-5c6a-4e46-95c6-89e79385c163'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99669', 'MBFL', now(), now(), '6c1d51b0-9213-404a-b7d8-c4fc384bd304'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99670', 'MBFL', now(), now(), '523b6896-d660-42c7-a8f9-e4603e75ccc9'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99671', 'MBFL', now(), now(), '2c1d481b-6ef3-49ab-8ae9-a9e6429575fd'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99672', 'MBFL', now(), now(), '702c69d2-5231-4267-8d8e-85d5817077d7'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99674', 'MBFL', now(), now(), '66b7f4fb-9098-40a8-a018-a5217ed9878d'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99675', 'MBFL', now(), now(), '2ab46ff9-9120-48af-ac05-73663dfd1571'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99676', 'MBFL', now(), now(), '488978c8-3c52-4a1a-9966-c04bba23ee37'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99677', 'MBFL', now(), now(), '30ceccbf-25b6-4862-b358-78f12e22ba06'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99678', 'MBFL', now(), now(), 'a4ed1190-85d9-4b20-8390-9a1b9a3bc0c4'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99679', 'MBFL', now(), now(), '1c87ddc2-ad88-4607-b826-f37da5fc8762'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99680', 'MBFL', now(), now(), '3b5dca39-d435-413c-9edf-3bb3a2b5005d'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99681', 'MBFL', now(), now(), '93acc862-3107-4f22-b270-e0c7d1f5f80b'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99682', 'MBFL', now(), now(), 'd5224770-83e3-4dc8-97af-24c147669dcc'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99683', 'MBFL', now(), now(), 'b9dcbc66-53d9-4f14-b51d-02171a3fdf5f'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99684', 'MBFL', now(), now(), '65a07b11-25cf-4fae-baf4-59d89677cfc2'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99685', 'MBFL', now(), now(), '0cc24afe-3579-41bf-8181-08725b45e3b0'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99686', 'MBFL', now(), now(), 'fd40734b-f683-43b2-9e6e-93eeda219aa9'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99687', 'MBFL', now(), now(), 'fe3c676b-a3d7-4d58-88d4-5a6ab3dc3aae'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99688', 'MBFL', now(), now(), '83cc5417-31e0-468c-a5b3-0495734e9504'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99689', 'MAPK', now(), now(), '68962696-2ba8-40ae-946d-8ab29dd3cd4b'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99690', 'MBFL', now(), now(), '92d71dc8-6601-4cc0-bd76-3584e402ceed'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99691', 'MBFL', now(), now(), '839bfff4-f486-462f-bf2c-560aa95f5b6e'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99692', 'MBFL', now(), now(), 'b3e45fb6-3e5f-452e-b355-08fa49e1f52b'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99693', 'MBFL', now(), now(), 'd3843234-0168-402a-821d-9a4666a54273'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99694', 'MBFL', now(), now(), '3ca39ea7-1f6d-4112-886e-cd4c6fc07476'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99695', 'MBFL', now(), now(), 'b865dfa9-c1c4-42bd-9253-8fa643ebf582'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99697', 'MAPS', now(), now(), '8e71753d-c45a-4a84-912e-cb6bb8a0ccef'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99701', 'MBFL', now(), now(), '951282d4-0523-450b-a636-c2bdadf2a38a'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99702', 'MBFL', now(), now(), 'fcab1e10-4645-4d3e-a4b7-00a9f54a2157'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99703', 'JEAT', now(), now(), '5f47676a-520d-4106-9889-009b0ab29726'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99704', 'MBFL', now(), now(), '328fd045-2e70-4bc2-a466-1319e2425b1f'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99705', 'MBFL', now(), now(), '37727f3a-6c6e-4d9e-890c-ec0279c7de0b'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99706', 'MBFL', now(), now(), 'c84810a5-660f-4200-a86f-46a17f038adf'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99707', 'MBFL', now(), now(), '7d090646-098b-4096-9012-b68182cf2e35'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99708', 'MBFL', now(), now(), '7a16c7b2-e624-4933-9dc4-b3be69849fe5'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99709', 'MBFL', now(), now(), 'bd590cc5-a624-4fb2-b37b-4b37a7ac863a'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99710', 'MBFL', now(), now(), '5fab3c20-38ee-44b6-9ae1-384b93462637'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99711', 'MBFL', now(), now(), '1d3a88e9-a0e0-4cce-b20a-9f0b6996b7e1'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99712', 'MBFL', now(), now(), 'acec5c52-6709-48cb-a6cb-0e58b05860ec'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99714', 'MBFL', now(), now(), 'ce621370-6656-480d-a071-89de4607d716'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99716', 'MBFL', now(), now(), 'b65f161a-0f33-4360-8905-c716b17943d4'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99720', 'MBFL', now(), now(), '19aa130f-0dee-46db-a054-729cddf9a257'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99721', 'MBFL', now(), now(), '715fde06-a1a7-4240-8e59-4b76dffdb144'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99722', 'MBFL', now(), now(), '4be97e0b-4237-4906-bb0d-8e1704e0b65b'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99723', 'MBFL', now(), now(), 'aad84c1d-7ba2-40de-92e5-74b2dd558fa9'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99724', 'MBFL', now(), now(), '8b8157b2-0c64-477f-a173-e26818caeffd'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99725', 'MBFL', now(), now(), '8f258372-966a-4565-9e22-61cdb5f88ef9'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99726', 'MBFL', now(), now(), '02f07ef0-ebad-4fb8-a50c-bdd140d87c49'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99727', 'MBFL', now(), now(), '63de42c5-eb6e-4471-9170-8d4d3fd88d87'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99729', 'MBFL', now(), now(), 'c12cf5c5-b3e0-4dff-a88f-39b8a22a950b'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99730', 'MBFL', now(), now(), '820b8fe5-2c4c-459a-850a-8326fd50ea57'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99731', 'JEAT', now(), now(), 'dd366219-6c3b-45c1-a59a-e04d0efe1a6d'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99732', 'MBFL', now(), now(), '32e2f9ec-805a-419b-a850-e4868c8eb13f'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99733', 'MBFL', now(), now(), '9762e6a0-a2dd-4da7-9cc5-4dfdfd21fad2'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99734', 'MBFL', now(), now(), 'f35587d4-41be-4e7a-8cc3-07e1f2a9e4b9'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99736', 'MBFL', now(), now(), 'a71189c1-784c-4d9c-925b-dcc6432c6a28'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99737', 'MBFL', now(), now(), '80a884f0-058a-46c0-8fdb-90d1d027f002'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99738', 'MBFL', now(), now(), '34cf2f93-66b3-43ab-a428-2cc2e4c6b143'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99739', 'MBFL', now(), now(), 'eadc1ca9-6de2-46ab-a015-acb813599670'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99740', 'MBFL', now(), now(), 'cc3f07af-485b-4256-8703-bf41a5967497'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99741', 'MBFL', now(), now(), '61409776-e0fa-47f4-825e-9c6f91ce2b10'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99742', 'MBFL', now(), now(), 'b46d81ef-9faa-49ec-85a3-4c3734d07126'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99743', 'MBFL', now(), now(), 'acb28741-502a-40c2-aa45-4a9b42d39405'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99744', 'MBFL', now(), now(), 'baf46567-31ea-481d-9ab9-e974ea261c2f'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99745', 'MBFL', now(), now(), 'babaac73-1c6b-4209-baf3-1e0c5d41dc7f'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99746', 'MBFL', now(), now(), 'ddc32535-73e0-4f13-ad2e-6294700c17cc'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99747', 'MBFL', now(), now(), '40a3c816-79a0-4f26-aa6a-2847835a45d1'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99748', 'MBFL', now(), now(), '5a3a2cce-4bc0-4bd2-98fe-7f71bc09c99e'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99749', 'MBFL', now(), now(), '212653a0-4a5a-4e48-b301-78b3f294fe16'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99750', 'MBFL', now(), now(), '2013baa1-1f2f-47f7-beb0-98f3171c6bf1'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99751', 'MBFL', now(), now(), 'a19e22ef-194e-4b48-858c-59ea04d48fcf'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99752', 'MBFL', now(), now(), 'e1ce6564-37d3-4fe4-8c19-f39e31c9d7cd'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99753', 'MBFL', now(), now(), '2dd6633b-4a67-4bff-879f-32bf88ec64a5'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99754', 'MBFL', now(), now(), '5fe4e773-573e-4052-b4b7-d5686366d03b'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99755', 'MBFL', now(), now(), '0383ed06-ff31-4fa7-851a-962dc7adf7d3'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99756', 'MBFL', now(), now(), '61726154-40a0-4f7d-82d0-b09f28a2f209'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99757', 'MBFL', now(), now(), '3bd35ddb-4d89-4e01-8dd1-e938bc5c0388'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99758', 'MBFL', now(), now(), '31c3a401-cc17-4e5a-bf22-d66e00a05528'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99759', 'MBFL', now(), now(), 'cc534b49-e72f-4a19-bbad-4dc5101c1373'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99760', 'MBFL', now(), now(), '56e2c9c0-f914-40f3-988c-7b88593f5513'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99761', 'MBFL', now(), now(), 'ccd849d7-e2ed-40ce-a353-9c93d57b4f92'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99762', 'MBFL', now(), now(), '1981bcff-5f4b-4358-92ea-93177783215f'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99763', 'MBFL', now(), now(), '298d0d8a-a19a-4498-937f-1ab233a85730'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99764', 'MBFL', now(), now(), '37352211-832f-4af7-8655-414ac02b8544'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99765', 'MBFL', now(), now(), 'c2dd65ee-9875-4e7d-9d34-46f529f8959b'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99766', 'MBFL', now(), now(), 'ad3283f4-74cb-403f-84a2-c14f510f83cd'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99767', 'MBFL', now(), now(), 'eb25b5f7-ed3b-4860-b337-5ee68b6c4534'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99768', 'MBFL', now(), now(), '92116116-8a7a-420c-83cd-5f9977401941'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99769', 'MBFL', now(), now(), 'c5a38d76-3bef-4e9d-8244-1741aa20ed10'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99770', 'MBFL', now(), now(), 'e7f0f266-019d-4bce-8921-6804e5e8cb0c'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99771', 'MBFL', now(), now(), '74f9319a-0970-4721-8fda-bfe4f777896b'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99772', 'MBFL', now(), now(), 'db7dc663-1443-4209-9a01-82f694a4dca1'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99773', 'MBFL', now(), now(), '474d4d25-1314-4bbf-ae04-25ffae18a7d4'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99774', 'MBFL', now(), now(), 'ea503792-8747-465c-ad89-c513004e1345'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99775', 'MBFL', now(), now(), 'e33ba93c-8ba2-4a3b-b8bc-f331a989e388'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99776', 'MBFL', now(), now(), 'ffc00def-ec8b-413d-9601-bf5587b510f4'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99777', 'MBFL', now(), now(), 'ce0ff3db-7d59-43af-923d-efdf4feb72cf'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99778', 'MBFL', now(), now(), '4235599e-4fd3-46e9-b733-de29dca74700'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99780', 'MBFL', now(), now(), '0aa94d7f-81bb-42f4-be8a-e14b2bc630c8'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99781', 'MBFL', now(), now(), '1b98f0bd-711c-48f0-87ed-9e5bff30ad60'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99782', 'MBFL', now(), now(), 'c7f7dd5b-7674-4b78-b1a5-0013fd979231'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99783', 'MBFL', now(), now(), '20152935-a8c8-45ad-a4cd-af2a945a8a17'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99784', 'MBFL', now(), now(), '58ec9aaa-e2d0-4732-9ffd-3b7563bb1c05'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99785', 'MBFL', now(), now(), '13f3eb0b-1534-4773-9fae-a86d39a829ae'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99786', 'MBFL', now(), now(), 'eeb04da3-f067-469b-8703-c3e9de365ad7'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99788', 'MBFL', now(), now(), '224088e2-afba-4b23-8361-9126c00445a8'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99789', 'MBFL', now(), now(), '8c123f36-f68d-461b-bd60-01cbd501ae17'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99790', 'MBFL', now(), now(), '1492fc25-8a4a-4fbc-a9be-433ad03d878e'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99791', 'MBFL', now(), now(), 'fda0d6c4-7a68-425b-9567-da8d368dbfa0'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99801', 'MAPK', now(), now(), '095789bc-136f-44e6-bf3f-b5a5a4ffad5c'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99802', 'MAPK', now(), now(), '1e73fbe5-0924-42dc-aedd-9c4aab511b90'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99803', 'MAPK', now(), now(), '281f58c0-fe6e-4e77-9035-6f1db1d4a8fd'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99811', 'MAPK', now(), now(), '6dcd4248-9c66-4bf3-8f4b-30dfd4add731'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99812', 'MAPK', now(), now(), '82579769-f363-4d68-b6f4-2586ac3f974c'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99820', 'MAPK', now(), now(), 'aecd46d3-dea5-4d0e-8409-b5b300ddded8'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99821', 'MAPK', now(), now(), '5a3ff675-8c07-4058-b5c6-8c19400f2f07'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99824', 'MAPK', now(), now(), 'e0cd0a98-4c4e-4d21-9adc-416fb4ce2449'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99825', 'MAPK', now(), now(), 'aa515936-aa46-4016-a487-c925b4dc16b2'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99826', 'MAPK', now(), now(), '553f410a-ed32-4517-a766-c665369d9369'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99827', 'MAPK', now(), now(), 'a275e877-48ba-4473-8064-43b3ab7b042b'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99829', 'MAPK', now(), now(), '7cb1babd-df8b-400f-9e5c-6c595bbcaa2f'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99830', 'MAPK', now(), now(), 'dcc9dd70-0984-4555-a371-e8f8bf583ecf'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99832', 'MAPK', now(), now(), 'a3740468-c12a-465d-b627-fd80bc921eb5'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99833', 'MAPK', now(), now(), '38eecaf7-4c2d-44c5-a8bd-ccde44ec6b89'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99835', 'MAPK', now(), now(), 'c914333a-4c88-404b-a17a-f51b4df9dac7'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99836', 'MAPK', now(), now(), 'fe065064-61f7-4c01-80f4-945fb1d6d26f'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99840', 'MAPK', now(), now(), '7c72b250-4d4b-41a2-b548-97a5b1e1c526'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99841', 'MAPK', now(), now(), '1a1c28b2-d5c7-4180-93ea-d66887ce7e26'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99850', 'MAPK', now(), now(), '21f9854e-2a61-4810-a4e3-ea09f1f2c59f'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99901', 'MAPK', now(), now(), '36ef16e6-d9a5-4706-a115-e11691ff1c37'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99903', 'MAPK', now(), now(), '76d5df09-e4f1-4b96-8df4-68bbeee29b00'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99918', 'MAPK', now(), now(), '4b6b34d9-40ec-459a-a337-5fbdde3aaa84'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99919', 'MAPK', now(), now(), 'af79bdf9-f4cf-494e-ad67-ddbb836e98d0'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99921', 'MAPK', now(), now(), '742e78df-6615-406b-b0f2-55deaec1fc09'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99922', 'MAPK', now(), now(), '99701216-788c-41d7-bdbb-98ff0f8e2224'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99923', 'MAPK', now(), now(), '3978cb58-70b6-4c23-a97b-d6e00cf7abcf'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99925', 'MAPK', now(), now(), 'bc7cb635-6287-4ecb-8f8c-9e6f66858441'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99926', 'MAPK', now(), now(), '9abec1b8-3f19-4616-aae2-8c8a54b44e48'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99927', 'MAPK', now(), now(), 'ba7adb39-9897-4e4d-b042-c4360cc25691'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99928', 'MAPK', now(), now(), '4f721fb2-7bcc-4a2a-a24b-cd3d00532311'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99929', 'MAPK', now(), now(), '0ed1ee93-f720-4e4c-b28a-4572e847ad15'); + +INSERT INTO postal_code_to_gblocs(postal_code, gbloc, created_at, updated_at, id) +VALUES ('99950', 'MAPK', now(), now(), '23c0f299-2b5c-44ff-b604-5efd70019f8d'); diff --git a/migrations/app/schema/20250103142533_update_postal_codes_and_gblocs_for_ak.up.sql b/migrations/app/schema/20250103142533_update_postal_codes_and_gblocs_for_ak.up.sql new file mode 100644 index 00000000000..a150e692932 --- /dev/null +++ b/migrations/app/schema/20250103142533_update_postal_codes_and_gblocs_for_ak.up.sql @@ -0,0 +1,159 @@ +delete from postal_code_to_gblocs where postal_code in ( +select uspr_zip_id from v_locations where state = 'AK'); + +drop view move_to_gbloc; +CREATE OR REPLACE VIEW move_to_gbloc AS +SELECT move_id, gbloc FROM ( + SELECT DISTINCT ON (sh.move_id) sh.move_id, s.affiliation, + COALESCE(pctg.gbloc, coalesce(pctg_oconus_bos.gbloc, coalesce(pctg_oconus.gbloc, pctg_ppm.gbloc))) AS gbloc + FROM mto_shipments sh + JOIN moves m ON sh.move_id = m.id + JOIN orders o on m.orders_id = o.id + JOIN service_members s on o.service_member_id = s.id + LEFT JOIN ( SELECT a.id AS address_id, + pctg_1.gbloc, pctg_1.postal_code + FROM addresses a + JOIN postal_code_to_gblocs pctg_1 ON a.postal_code::text = pctg_1.postal_code::text) pctg ON pctg.address_id = sh.pickup_address_id + LEFT JOIN ( SELECT ppm.shipment_id, + pctg_1.gbloc + FROM ppm_shipments ppm + JOIN addresses ppm_address ON ppm.pickup_postal_address_id = ppm_address.id + JOIN postal_code_to_gblocs pctg_1 ON ppm_address.postal_code::text = pctg_1.postal_code::text) pctg_ppm ON pctg_ppm.shipment_id = sh.id + LEFT JOIN ( SELECT a.id AS address_id, + cast(jr.code as varchar) AS gbloc, ga.department_indicator + FROM addresses a + JOIN re_oconus_rate_areas ora ON a.us_post_region_cities_id = ora.us_post_region_cities_id + JOIN gbloc_aors ga ON ora.id = ga.oconus_rate_area_id + JOIN jppso_regions jr ON ga.jppso_regions_id = jr.id + ) pctg_oconus_bos ON pctg_oconus_bos.address_id = sh.pickup_address_id + and case when s.affiliation = 'AIR_FORCE' THEN 'AIR_AND_SPACE_FORCE' + when s.affiliation = 'SPACE_FORCE' THEN 'AIR_AND_SPACE_FORCE' + when s.affiliation = 'NAVY' THEN 'NAVY_AND_MARINES' + when s.affiliation = 'MARINES' THEN 'NAVY_AND_MARINES' + else s.affiliation + end = pctg_oconus_bos.department_indicator + LEFT JOIN ( SELECT a.id AS address_id, + cast(pctg_1.code as varchar) AS gbloc, ga.department_indicator + FROM addresses a + JOIN re_oconus_rate_areas ora ON a.us_post_region_cities_id = ora.us_post_region_cities_id + JOIN gbloc_aors ga ON ora.id = ga.oconus_rate_area_id + JOIN jppso_regions pctg_1 ON ga.jppso_regions_id = pctg_1.id + ) pctg_oconus ON pctg_oconus.address_id = sh.pickup_address_id and pctg_oconus.department_indicator is null + WHERE sh.deleted_at IS NULL + ORDER BY sh.move_id, sh.created_at) as m; + + +DROP FUNCTION IF EXISTS get_address_gbloc; + +CREATE OR REPLACE FUNCTION public.get_address_gbloc( + address_id UUID, + affiliation TEXT, + OUT gbloc TEXT +) +RETURNS TEXT AS $$ +DECLARE + is_oconus BOOLEAN; + v_count INT; + v_bos_count INT; + v_dept_ind TEXT; +BEGIN + is_oconus := get_is_oconus(address_id); + + IF affiliation in ('AIR_FORCE','SPACE_FORCE') THEN + v_dept_ind := 'AIR_AND_SPACE_FORCE'; + ELSIF affiliation in ('MARINES','NAVY') THEN + v_dept_ind := 'NAVY_AND_MARINES'; + ELSE v_dept_ind := affiliation; + END IF; + + IF is_oconus THEN + + SELECT count(*) + INTO v_count + FROM addresses a, + re_oconus_rate_areas o, + jppso_regions j, + gbloc_aors g + WHERE a.us_post_region_cities_id = o.us_post_region_cities_id + and o.id = g.oconus_rate_area_id + and j.id = g.jppso_regions_id + and a.id = address_id; + + IF v_count > 1 THEN + + --check for gbloc by bos + SELECT count(*) + INTO v_bos_count + FROM addresses a, + re_oconus_rate_areas o, + jppso_regions j, + gbloc_aors g + WHERE a.us_post_region_cities_id = o.us_post_region_cities_id + and o.id = g.oconus_rate_area_id + and j.id = g.jppso_regions_id + and a.id = address_id + and g.department_indicator = v_dept_ind; + + IF v_bos_count = 1 THEN + + SELECT j.code + INTO gbloc + FROM addresses a, + re_oconus_rate_areas o, + jppso_regions j, + gbloc_aors g + WHERE a.us_post_region_cities_id = o.us_post_region_cities_id + and o.id = g.oconus_rate_area_id + and j.id = g.jppso_regions_id + and a.id = address_id + and g.department_indicator = v_dept_ind; + + ELSE + + SELECT j.code + INTO gbloc + FROM addresses a, + re_oconus_rate_areas o, + jppso_regions j, + gbloc_aors g + WHERE a.us_post_region_cities_id = o.us_post_region_cities_id + and o.id = g.oconus_rate_area_id + and j.id = g.jppso_regions_id + and a.id = address_id + and g.department_indicator IS NULL; + + END IF; + + ELSE + + SELECT j.code + INTO gbloc + FROM addresses a, + re_oconus_rate_areas o, + jppso_regions j, + gbloc_aors g + WHERE a.us_post_region_cities_id = o.us_post_region_cities_id + and o.id = g.oconus_rate_area_id + and j.id = g.jppso_regions_id + and a.id = address_id; + + END IF; + + ELSE --is conus + + SELECT j.gbloc + INTO gbloc + FROM addresses a, + v_locations o, + postal_code_to_gblocs j + WHERE a.us_post_region_cities_id = o.uprc_id + and o.uspr_zip_id = j.postal_code + and a.id = address_id; + + END IF; + + IF gbloc IS NULL THEN + RAISE EXCEPTION 'GBLOC not found for address ID % for affiliation %', address_id, affiiation; + END IF; +END; +$$ LANGUAGE plpgsql; \ No newline at end of file diff --git a/migrations/app/schema/20250123173216_add_destination_queue_db_func_and_gbloc_view.up.sql b/migrations/app/schema/20250123173216_add_destination_queue_db_func_and_gbloc_view.up.sql new file mode 100644 index 00000000000..5148f0f57d7 --- /dev/null +++ b/migrations/app/schema/20250123173216_add_destination_queue_db_func_and_gbloc_view.up.sql @@ -0,0 +1,502 @@ +--insert USMC gbloc +insert into jppso_regions values ('85b324ae-1a0d-4f7d-971f-ea509dcc73d7', 'USMC','USMC',now(),now()); + +--insert USMC AORs +INSERT INTO gbloc_aors (id,jppso_regions_id,oconus_rate_area_id,department_indicator,shipment_type,is_active,created_at,updated_at) VALUES + ('a8eb35e2-275e-490b-9945-1971b954b958'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'e418be11-2b6f-4714-b026-e293528c50bd'::uuid,'MARINES',NULL,true,now(),now()), + ('ada1b48d-d2e0-481a-8a2e-a265a824647d'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'b41c5636-96dd-4f0d-a18e-eebb17f97ea5'::uuid,'MARINES',NULL,true,now(),now()), + ('588af482-7cd7-42ea-8e05-49dce645ecbe'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'02f32a6a-0338-4545-8437-059862892d2c'::uuid,'MARINES',NULL,true,now(),now()), + ('1ff3bed7-bbf3-432d-9da3-d76264d72913'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'0f128476-d52a-418c-8ba0-c8bfd1c32629'::uuid,'MARINES',NULL,true,now(),now()), + ('0853a854-98b2-4363-a2b1-db14c44dde2f'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'081f84c3-17ec-4ff6-97ce-d5c44a8e4a28'::uuid,'MARINES',NULL,true,now(),now()), + ('21c1ba40-2533-4196-9eb5-6ffddff3a794'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'ce7cdd91-e323-43a6-a604-daaa6bf8be06'::uuid,'MARINES',NULL,true,now(),now()), + ('19ca4073-8736-453e-bb0d-9b13e3b557b0'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'655050d4-711a-43b7-b06d-828ec990c35e'::uuid,'MARINES',NULL,true,now(),now()), + ('a9c2131e-09c3-480d-ba3e-0c144de18aa5'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'455a34af-30a8-4a98-a62b-6f40fd7f047b'::uuid,'MARINES',NULL,true,now(),now()), + ('649e72f8-cac8-483f-a9ed-c9659e37545b'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'1bf1daee-51bb-4c28-aac8-a126ef596486'::uuid,'MARINES',NULL,true,now(),now()), + ('7173f871-f948-4eed-86ae-5e977b16c426'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'15b1d852-0dde-4e1b-b3c6-e08bbc714db3'::uuid,'MARINES',NULL,true,now(),now()); +INSERT INTO gbloc_aors (id,jppso_regions_id,oconus_rate_area_id,department_indicator,shipment_type,is_active,created_at,updated_at) VALUES + ('4f626e2a-cad0-4b4d-baa8-3101275bac23'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'d63de5bb-379b-4f3b-b4c1-554b9746d311'::uuid,'MARINES',NULL,true,now(),now()), + ('de59c604-9119-48fc-bf3f-883de17b7ee6'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'95d142f8-b50a-4108-b5e2-fbd3b7022d3b'::uuid,'MARINES',NULL,true,now(),now()), + ('1cec884c-9e34-42fe-8887-1e8b8fa1cd2e'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'922bb7da-d0e9-431c-a493-95a861dca929'::uuid,'MARINES',NULL,true,now(),now()), + ('0f24b453-e3bc-47ec-86b5-8d8937f65504'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'79aef0ca-9065-4c0e-a134-2889b250cc38'::uuid,'MARINES',NULL,true,now(),now()), + ('2d55560a-7d0a-474f-a0f9-b31c5be8d80e'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'1f181025-e410-41ac-935b-4b5147353f84'::uuid,'MARINES',NULL,true,now(),now()), + ('abcc37f6-9209-4639-8fa1-c8d5f6e4e77d'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'d9ede620-c3f1-4f8d-b60b-eb93664382f7'::uuid,'MARINES',NULL,true,now(),now()), + ('3ac990d2-5df4-4889-a943-2710f818e75a'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'bd27700b-3094-46cc-807b-f18472cbfaf0'::uuid,'MARINES',NULL,true,now(),now()), + ('f3084090-680f-4656-947a-eb2e773e4076'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'2f4a1689-ee65-45fa-9d0c-debd9344f8b9'::uuid,'MARINES',NULL,true,now(),now()), + ('a35ac50b-09a1-46ef-969e-17569717ee10'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'20c52934-2588-4d8f-b3ed-c046d771f4e9'::uuid,'MARINES',NULL,true,now(),now()), + ('107c1479-e6d9-44cb-8342-ac934055074d'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'15fe364b-add5-4ade-bdd9-38fe442616fb'::uuid,'MARINES',NULL,true,now(),now()); +INSERT INTO gbloc_aors (id,jppso_regions_id,oconus_rate_area_id,department_indicator,shipment_type,is_active,created_at,updated_at) VALUES + ('843db089-67cb-463d-a255-1d198f4f7aaa'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'e5a1248e-3870-4a4c-9c9d-2056234eb64a'::uuid,'MARINES',NULL,true,now(),now()), + ('ac820ac9-d380-4c11-9103-172795658e1f'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'efc92db1-4b06-49ab-a295-a98f3f6c9c04'::uuid,'MARINES',NULL,true,now(),now()), + ('dca7ccd2-e438-4f82-8b76-9b61fbf2a593'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'13474ce5-8839-4af7-b975-c3f70ccdab7b'::uuid,'MARINES',NULL,true,now(),now()), + ('def1095b-2a5c-4f7c-8889-9fde15a7ec06'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'d3b05c5e-6faa-4fa9-b725-0904f8a4f3d7'::uuid,'MARINES',NULL,true,now(),now()), + ('d5fbc738-ee31-4c51-8fd4-bbb8db941dc1'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'e5f849fe-5672-4d0d-881c-078e56eea33d'::uuid,'MARINES',NULL,true,now(),now()), + ('ac8c75fe-f637-429d-80fa-913321a65372'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'fca7c60e-fbd9-4885-afdb-ae41c521b560'::uuid,'MARINES',NULL,true,now(),now()), + ('c33eb1f8-b0fc-4670-af5e-5bd423eca6e7'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'0d52a0f0-f39c-4d34-9387-2df45a5810d4'::uuid,'MARINES',NULL,true,now(),now()), + ('188ea995-b8b7-4ce0-97a9-f553f3b72c2f'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'af008e75-81d5-4211-8204-4964c78e70d9'::uuid,'MARINES',NULL,true,now(),now()), + ('4f13c1a6-059b-4aa2-9250-4316e60da2a7'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'dd689e55-af29-4c76-b7e0-c2429ea4833c'::uuid,'MARINES',NULL,true,now(),now()), + ('67e1ff6f-b79b-45cf-b250-3d4ec89bebae'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'60e08330-6869-4586-8198-35f7a4ae9ea7'::uuid,'MARINES',NULL,true,now(),now()); +INSERT INTO gbloc_aors (id,jppso_regions_id,oconus_rate_area_id,department_indicator,shipment_type,is_active,created_at,updated_at) VALUES + ('3a7c679c-0439-4030-8f7e-f6d8e92720d7'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'f7478e79-dbfe-46c8-b337-1e7c46df79dc'::uuid,'MARINES',NULL,true,now(),now()), + ('db91f133-a301-4c87-af9f-6c10584063e6'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'486d7dd4-f51f-4b13-88fc-830b5b15f0a8'::uuid,'MARINES',NULL,true,now(),now()), + ('6b83cc22-36a9-470e-9f43-e65ade5e8a66'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'f66edf62-ba5e-47f8-8264-b6dc9e7dd9ba'::uuid,'MARINES',NULL,true,now(),now()), + ('3df30221-acd3-4428-890c-3a5ef5296cb1'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'0052c55a-d9d7-46b0-9328-58d3911f61b4'::uuid,'MARINES',NULL,true,now(),now()), + ('bae4c9c6-94d8-4ad0-bfc0-7642f5353199'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'16a51fd1-04ed-432a-a8d7-9f17c1de095d'::uuid,'MARINES',NULL,true,now(),now()), + ('1cd873ff-d170-4f48-8f5b-5c5146052d68'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'64b4756f-437d-4aa5-a95e-c396f0cafcbb'::uuid,'MARINES',NULL,true,now(),now()), + ('eb4d870b-8d66-4135-b294-8992e56ad76f'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'f2de1da5-a737-4493-b3f7-7700944a5b62'::uuid,'MARINES',NULL,true,now(),now()), + ('e8c0709c-1f08-4d3e-b848-72ab5b524677'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'7a9c2adb-0562-42c1-a5f1-81710dd19590'::uuid,'MARINES',NULL,true,now(),now()), + ('3c53df36-ee6b-4bc0-a5ca-cedc1dc3c32e'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'e713eed6-35a6-456d-bfb2-0e0646078ab8'::uuid,'MARINES',NULL,true,now(),now()), + ('7cbc7e6c-4da7-47a1-ac93-171b89dba1e0'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'a4594957-0ec6-4edc-85c2-68871f4f6359'::uuid,'MARINES',NULL,true,now(),now()); +INSERT INTO gbloc_aors (id,jppso_regions_id,oconus_rate_area_id,department_indicator,shipment_type,is_active,created_at,updated_at) VALUES + ('d22cb1d2-79b4-45c9-bb6f-8acef54a67b0'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'acd4d2f9-9a49-4a73-be14-3515f19ba0d1'::uuid,'MARINES',NULL,true,now(),now()), + ('5b5e7a5a-d027-44f2-9b4f-f25c1a91bc00'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'c8300ab6-519c-4bef-9b81-25e7334773ca'::uuid,'MARINES',NULL,true,now(),now()), + ('21307477-912d-40ca-a399-6dfebcc322ea'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'67eca2ce-9d88-44ca-bb17-615f3199415c'::uuid,'MARINES',NULL,true,now(),now()), + ('82282efb-7fef-4a6d-a260-a18d2f21fa8d'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'149c3a94-abb1-4af0-aabf-3af019d5e243'::uuid,'MARINES',NULL,true,now(),now()), + ('3bdad313-d414-4842-8e6e-3675e20d78eb'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'87c09b47-058e-47ea-9684-37a8ac1f7120'::uuid,'MARINES',NULL,true,now(),now()), + ('db80b591-045d-4907-9b77-6694fe34e3ed'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'0ba81e85-f175-435a-a7c2-a22d0c44cc7b'::uuid,'MARINES',NULL,true,now(),now()), + ('05970a8a-28aa-454f-a28e-31327a2415dd'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'946256dc-1572-4201-b5ff-464da876f5ff'::uuid,'MARINES',NULL,true,now(),now()), + ('c1b3e0be-0463-4dfc-ab22-016037b41a05'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'5d381518-6beb-422e-8c57-4682b87ff1fe'::uuid,'MARINES',NULL,true,now(),now()), + ('1a92f4b0-4060-4f1b-9b45-b3fc47c5f08d'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'b07fb701-2c9b-4847-a459-76b1f47aa872'::uuid,'MARINES',NULL,true,now(),now()), + ('73794c53-a915-41af-b93d-5ada2e174409'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'b6c51584-f3e8-4c9e-9bdf-f7cac0433319'::uuid,'MARINES',NULL,true,now(),now()); +INSERT INTO gbloc_aors (id,jppso_regions_id,oconus_rate_area_id,department_indicator,shipment_type,is_active,created_at,updated_at) VALUES + ('c03994c2-9e2a-4888-a5c2-c81ee05eba31'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'6097d01d-78ef-40d5-8699-7f8a8e48f4e7'::uuid,'MARINES',NULL,true,now(),now()), + ('ae6a55fd-2171-425a-9716-56d3fb9452e3'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'e48a3602-7fdd-4527-a8a7-f244fb331228'::uuid,'MARINES',NULL,true,now(),now()), + ('f052acf4-7d4a-4061-a2f4-ba19ff17ec4d'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'df47ef29-e902-4bd3-a32d-88d6187399b3'::uuid,'MARINES',NULL,true,now(),now()), + ('10b47428-bef7-4cfe-8564-2ccb654d514a'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'0f4eddf9-b727-4725-848e-3d9329553823'::uuid,'MARINES',NULL,true,now(),now()), + ('4a547501-6aae-4886-be5c-e5a0fad05441'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'d16ebe80-2195-48cf-ba61-b5efb8212754'::uuid,'MARINES',NULL,true,now(),now()), + ('d99cbe3a-84a0-4a2c-8e05-41ce066570ea'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'093268d0-597b-40bd-882a-8f385480bc68'::uuid,'MARINES',NULL,true,now(),now()), + ('ad09f13c-9dd9-468b-ab92-ad3e2d77c905'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'edb8b022-9534-44e7-87ea-e93f5451f057'::uuid,'MARINES',NULL,true,now(),now()), + ('362482c6-7770-49f4-86c9-89e2990e5345'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'4c62bb35-4d2a-4995-9c4f-8c665f2f6d3e'::uuid,'MARINES',NULL,true,now(),now()), + ('45994e2f-1aa4-4aa1-8631-a347a4463bc2'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'58ccfcc5-ded6-4f91-8cb7-8687bc56c4c6'::uuid,'MARINES',NULL,true,now(),now()), + ('b4fd2bf2-05b2-4429-afcb-ebbae512fd2b'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'dbc839c6-7b56-45b0-ab36-a0e77b0d538c'::uuid,'MARINES',NULL,true,now(),now()); +INSERT INTO gbloc_aors (id,jppso_regions_id,oconus_rate_area_id,department_indicator,shipment_type,is_active,created_at,updated_at) VALUES + ('5aa5f596-a9bb-4f37-af0b-6e0cfbfbc711'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'c77e434a-1bf9-44c6-92aa-d377d72d1d44'::uuid,'MARINES',NULL,true,now(),now()), + ('c7bc79d4-525e-496d-93bd-2ea76b32baf4'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'89533190-e613-4c36-99df-7ee3871bb071'::uuid,'MARINES',NULL,true,now(),now()), + ('5bc99ccb-7010-4d2f-99a0-9277eda982ba'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'c86cb50a-99f6-41ed-8e9d-f096bd5cadca'::uuid,'MARINES',NULL,true,now(),now()), + ('dc97dd55-213b-4212-8c1a-aaee7b92fc55'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'b65bd7c4-6251-4682-aa07-77f761c363af'::uuid,'MARINES',NULL,true,now(),now()), + ('3a4daddc-a377-440f-bb5f-d33024374e3e'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'88df8618-798a-4a12-9b14-a7267a6cfd7f'::uuid,'MARINES',NULL,true,now(),now()), + ('e729c30a-0bec-424a-919a-45cbe31998e9'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'15894c4f-eb1a-4b6b-8b3f-e3abc4eeee8d'::uuid,'MARINES',NULL,true,now(),now()), + ('74b6df4f-08ea-48fb-9628-15c3f47f3a27'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'83fd3eb7-6269-46e2-84e1-f6180f40b9e8'::uuid,'MARINES',NULL,true,now(),now()), + ('643112a7-71a9-41d1-97f6-92aee969478a'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'b0f95e07-e3d1-4403-a402-50be9a542cf9'::uuid,'MARINES',NULL,true,now(),now()), + ('73b35029-077b-4d30-8f5a-34c3785f6e96'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'cef18ff2-8f48-47c0-8062-a40f9dec641c'::uuid,'MARINES',NULL,true,now(),now()), + ('9d8862ec-4358-497a-8154-65a83c676261'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'15eefe71-55ae-40b0-8bb5-f1952fcf45c8'::uuid,'MARINES',NULL,true,now(),now()); +INSERT INTO gbloc_aors (id,jppso_regions_id,oconus_rate_area_id,department_indicator,shipment_type,is_active,created_at,updated_at) VALUES + ('8d5591d4-fcc4-44a9-babd-b575672ad6a9'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'d3c5d0a7-0477-44f6-8279-f6b9fa7b3436'::uuid,'MARINES',NULL,true,now(),now()), + ('c1057fc7-1c8b-44e2-a175-131ff0d7429f'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'8b89e7d7-cb36-40bd-ba14-699f1e4b1806'::uuid,'MARINES',NULL,true,now(),now()), + ('ae7949e2-9504-4874-92be-98460e8126da'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'5b833661-8fda-4f2a-9f2b-e1f4c21749a4'::uuid,'MARINES',NULL,true,now(),now()), + ('acf2cacd-0d4f-4de1-afdc-2eb1e72eeb80'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'38bed277-7990-460d-ad27-a69559638f42'::uuid,'MARINES',NULL,true,now(),now()), + ('c66c3d59-def9-4e08-8bee-5b2bacfc5cfd'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'67081e66-7e84-4bac-9c31-aa3e45bbba23'::uuid,'MARINES',NULL,true,now(),now()), + ('1f8cd63a-8dfe-4357-9ac5-2bef71f9d564'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'99e3f894-595f-403a-83f5-f7e035dd1f20'::uuid,'MARINES',NULL,true,now(),now()), + ('3e8030da-8316-4330-abea-35452e39fa61'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'1c0a5988-492f-4bc2-8409-9a143a494248'::uuid,'MARINES',NULL,true,now(),now()), + ('ce3c740a-b0a2-4a55-9abe-c2426fb8d821'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'63e10b54-5348-4362-932e-6613a8db4d42'::uuid,'MARINES',NULL,true,now(),now()), + ('9e913f22-287f-4e42-9544-46d9c6741db7'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'437e9930-0625-4448-938d-ba93a0a98ab5'::uuid,'MARINES',NULL,true,now(),now()), + ('d0ae21fe-07c0-40ee-9aa3-877d6d6a6bb9'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'87d3cb47-1026-4f42-bff6-899ff0fa7660'::uuid,'MARINES',NULL,true,now(),now()); +INSERT INTO gbloc_aors (id,jppso_regions_id,oconus_rate_area_id,department_indicator,shipment_type,is_active,created_at,updated_at) VALUES + ('6f8d7c90-7682-41b7-b5cc-9d4aeb2e22ef'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'0115586e-be8c-4808-b65a-d417fad19238'::uuid,'MARINES',NULL,true,now(),now()), + ('cf7f39c0-8f6b-4598-85db-f465241e66f4'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'6638a77d-4b91-48f6-8241-c87fbdddacd1'::uuid,'MARINES',NULL,true,now(),now()), + ('296a8951-19b1-4868-9937-aef61bb73106'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'97c16bc3-e174-410b-9a09-a0db31420dbc'::uuid,'MARINES',NULL,true,now(),now()), + ('cdcec10e-5300-443f-9aae-7d8ce07142b0'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'3c6c5e35-1281-45fc-83ee-e6d656e155b6'::uuid,'MARINES',NULL,true,now(),now()), + ('e638701f-f8fc-48c0-b2e0-db134b9ece1f'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'6af248be-e5a8-49e9-a9e2-516748279ab5'::uuid,'MARINES',NULL,true,now(),now()), + ('ed4f4905-b1cf-4e57-beac-bc0a2d167c71'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'3580abe3-84da-4b46-af7b-d4379e6cff46'::uuid,'MARINES',NULL,true,now(),now()), + ('2a8b16c9-99f8-43ca-a759-c4884f8f7b24'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'f3bb397e-04e6-4b37-9bf3-b3ebab79a9b6'::uuid,'MARINES',NULL,true,now(),now()), + ('70530105-a4ab-4af3-ba02-9e4cf81237fa'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'f9bfe297-4ee0-4f76-a4bd-64b3a514af5d'::uuid,'MARINES',NULL,true,now(),now()), + ('61e17c04-ed7b-4da9-816a-1b6343086d94'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'70f11a71-667b-422d-ae37-8f25539f7782'::uuid,'MARINES',NULL,true,now(),now()), + ('19d5158f-96a6-48ef-8dd9-b831c582c9c4'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'baf66a9a-3c8a-49e7-83ea-841b9960e184'::uuid,'MARINES',NULL,true,now(),now()); +INSERT INTO gbloc_aors (id,jppso_regions_id,oconus_rate_area_id,department_indicator,shipment_type,is_active,created_at,updated_at) VALUES + ('91043072-657f-4b2a-b5d1-42d8f6a7ba38'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'e96d46b1-3ab7-4b29-b798-ec3b728dd6a1'::uuid,'MARINES',NULL,true,now(),now()), + ('a3dc835e-3989-4476-b560-006745a884bc'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'e4171b5b-d26c-43b3-b41c-68b43bcbb079'::uuid,'MARINES',NULL,true,now(),now()), + ('0cf1dc14-0c9a-4262-9cab-db73c64f6e36'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'a0651bec-1258-4e36-9c76-155247e42c0a'::uuid,'MARINES',NULL,true,now(),now()), + ('e03b53cb-386f-4e1e-ac93-cd1a9260c6b4'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'737a8e63-af19-4902-a4b5-8f80e2268e4b'::uuid,'MARINES',NULL,true,now(),now()), + ('8b3f1142-f6d4-4c2d-9e75-9ab3568742f7'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'870df26e-2c50-4512-aa2e-61094cfbc3e1'::uuid,'MARINES',NULL,true,now(),now()), + ('5f5383b8-f29e-4b9f-8798-99575440c888'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'09dc6547-d346-40c3-93fb-fb7be1fa1b3e'::uuid,'MARINES',NULL,true,now(),now()), + ('1f7a198c-5f62-4f8c-bf91-19d7cdef9bae'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'43d7d081-bb32-4544-84f1-419fe0cb76e1'::uuid,'MARINES',NULL,true,now(),now()), + ('56c17bab-a124-4710-a047-0d67d30a9610'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'d7e57942-9c83-4138-baa0-70e8b5f08598'::uuid,'MARINES',NULL,true,now(),now()), + ('aad1440d-acaf-4ba8-9564-da97ab9ba651'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'c2f06691-5989-41a3-a848-19c9f0fec5df'::uuid,'MARINES',NULL,true,now(),now()), + ('6cc24224-2298-4023-888f-5e624e585171'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'5263a9ed-ff4d-42cc-91d5-dbdefeef54d1'::uuid,'MARINES',NULL,true,now(),now()); +INSERT INTO gbloc_aors (id,jppso_regions_id,oconus_rate_area_id,department_indicator,shipment_type,is_active,created_at,updated_at) VALUES + ('88cd8184-7e3a-48cf-bb72-a9e1c3666cc4'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'54ab3a49-6d78-4922-bac1-94a722b9859a'::uuid,'MARINES',NULL,true,now(),now()), + ('11fdac1c-7ae9-49ea-bee4-90d4582f7c6d'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'3b6fe2e9-9116-4a70-8eef-96205205b0e3'::uuid,'MARINES',NULL,true,now(),now()), + ('83c88ffb-5182-42b3-93f4-635556d8caaf'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'ba0017c8-5d48-4efe-8802-361d2f2bc16d'::uuid,'MARINES',NULL,true,now(),now()), + ('802f7a5f-8ce3-4c40-975a-83cf0ec502fc'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'af65234a-8577-4f6d-a346-7d486e963287'::uuid,'MARINES',NULL,true,now(),now()), + ('5197eed4-f6ae-4f70-b640-b67714b73f87'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'25f62695-ba9b-40c3-a7e4-0c078731123d'::uuid,'MARINES',NULL,true,now(),now()), + ('50d675ab-4064-4edb-8f1d-5739b0318ed9'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'b0422b13-4afe-443e-901f-fe652cde23a4'::uuid,'MARINES',NULL,true,now(),now()), + ('a3733567-2b57-4f12-9390-967e04bc1453'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'ecbc1d89-9cf6-4f52-b453-3ba473a0ff4e'::uuid,'MARINES',NULL,true,now(),now()), + ('6a321494-cdd8-4372-90a1-6a6c67f4e220'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'4e85cb86-e9dd-4c7c-9677-e0a327ac895c'::uuid,'MARINES',NULL,true,now(),now()), + ('99d37d3c-be31-4d3e-9c5e-c9d816a46014'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'7f9dd10d-100e-4252-9786-706349f456ca'::uuid,'MARINES',NULL,true,now(),now()), + ('e9b4c884-ad7f-4c1a-8815-05353834f5c3'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'5451f8d7-60c5-4e22-bbf6-d9af8e6ace54'::uuid,'MARINES',NULL,true,now(),now()); +INSERT INTO gbloc_aors (id,jppso_regions_id,oconus_rate_area_id,department_indicator,shipment_type,is_active,created_at,updated_at) VALUES + ('cfaa046e-6be5-4178-a451-d368317ecb86'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'9e9cba85-7c39-4836-809d-70b54baf392e'::uuid,'MARINES',NULL,true,now(),now()), + ('9b509efb-12d9-42aa-a85a-ffb026866b56'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'f7470914-cf48-43be-b431-a3ca2fe5b290'::uuid,'MARINES',NULL,true,now(),now()), + ('7e54d995-b7bd-457c-bd97-0fd76891402e'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'5a0d3cc1-b866-4bde-b67f-78d565facf3e'::uuid,'MARINES',NULL,true,now(),now()), + ('1357aadd-b420-42c4-8a39-bab8027fa910'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'e629b95a-ec5b-4fc4-897f-e0d1050e1ec6'::uuid,'MARINES',NULL,true,now(),now()), + ('56fbbf0f-e819-41dd-802d-4e677aecd1c9'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'d68a626f-935a-4eb1-ba9b-6829feeff91c'::uuid,'MARINES',NULL,true,now(),now()), + ('bfc2dc53-896f-4f29-92c7-9a7a392b22f2'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'ed496f6e-fd34-48d1-8586-63a1d305c49c'::uuid,'MARINES',NULL,true,now(),now()), + ('d015e8b1-86ea-489f-979d-458ae35ae8d6'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'153b62b2-b1b8-4b9d-afa5-53df4150aba4'::uuid,'MARINES',NULL,true,now(),now()), + ('1f32e712-8b5e-4ae4-b409-c5c92337aed8'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'0020441b-bc0c-436e-be05-b997ca6a853c'::uuid,'MARINES',NULL,true,now(),now()), + ('a8a85e00-e657-41a2-8f32-84bdd9c92ec8'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'a8ae9bb9-e9ac-49b4-81dc-336b8a0dcb54'::uuid,'MARINES',NULL,true,now(),now()), + ('4ad1a57f-0e9e-4405-9a08-0ffa211fc8ce'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'1aa43046-8d6b-4249-88dc-b259d86c0cb8'::uuid,'MARINES',NULL,true,now(),now()); +INSERT INTO gbloc_aors (id,jppso_regions_id,oconus_rate_area_id,department_indicator,shipment_type,is_active,created_at,updated_at) VALUES + ('dd765820-ffa5-4673-a347-fbe3464cd2d8'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'84b50723-95fc-41d1-8115-a734c7e53f66'::uuid,'MARINES',NULL,true,now(),now()), + ('6eff7586-59bd-4638-809b-5cc346646dc9'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'63dc3f78-235e-4b1c-b1db-459d7f5ae25f'::uuid,'MARINES',NULL,true,now(),now()), + ('428b0d7a-3848-4882-a5cc-80d5ae3500d6'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'4bd4c579-c163-4b1b-925a-d852d5a12642'::uuid,'MARINES',NULL,true,now(),now()), + ('9f8311f3-e191-4383-8fb8-2b58cd545dd4'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'ce7f1fc9-5b94-43cb-b398-b31cb6350d6a'::uuid,'MARINES',NULL,true,now(),now()), + ('81e3e6fe-7db3-49ff-b18c-8b078e3d129e'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'4a6a3260-e1ec-4d78-8c07-d89f1405ca16'::uuid,'MARINES',NULL,true,now(),now()), + ('4cf1c40f-60f0-4a47-a351-471720ba0fd3'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'658274b5-720c-4a70-ba9d-249614d85ebc'::uuid,'MARINES',NULL,true,now(),now()), + ('0754978b-d11e-4f2c-b59c-3252d2735b26'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'41f0736c-6d26-4e93-9668-860e9f0e222a'::uuid,'MARINES',NULL,true,now(),now()), + ('c9b8305d-2e16-46a7-9b7c-b3edeb6f8e93'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'c2a8e8c3-dddc-4c0f-a23a-0b4e2c20af0d'::uuid,'MARINES',NULL,true,now(),now()), + ('a8768e6d-1a6d-449a-9f2e-2e198dcd6e00'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'0f1e1c87-0497-4ee2-970d-21ac2d2155db'::uuid,'MARINES',NULL,true,now(),now()), + ('cf292129-d543-4632-9cb3-b074279e42be'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'e40b411d-55f0-4470-83d0-0bbe11fa77dd'::uuid,'MARINES',NULL,true,now(),now()); +INSERT INTO gbloc_aors (id,jppso_regions_id,oconus_rate_area_id,department_indicator,shipment_type,is_active,created_at,updated_at) VALUES + ('3f07cedf-ad90-465e-95a5-ce44a2f088b8'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'2632b4e5-c6cb-4e64-8924-0b7e4b1115ec'::uuid,'MARINES',NULL,true,now(),now()), + ('42a2d93b-9dea-4c63-b0a7-c39364aacf75'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'1336deb9-5c87-409d-8051-4ab9f211eb29'::uuid,'MARINES',NULL,true,now(),now()), + ('64fe0d14-98f7-4f73-9aa3-a19617b2d8c3'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'7a6d3b5b-81a6-4db5-b2ab-ecbfd6bd7941'::uuid,'MARINES',NULL,true,now(),now()), + ('3ab04740-9f13-47f8-a80e-b63ab5b67590'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'91b69254-5976-4839-a31d-972e9958d9cf'::uuid,'MARINES',NULL,true,now(),now()), + ('3be8e483-6bce-4a7d-a3bd-fc1485e79818'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'166f3629-79b9-451a-90a3-c43680929a2f'::uuid,'MARINES',NULL,true,now(),now()), + ('ddf69dcb-345e-47c1-a585-ce24d0854de5'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'4fe05eb4-1b1c-4d4a-a185-0b039ac64835'::uuid,'MARINES',NULL,true,now(),now()), + ('fe9e365f-98a5-4658-a58d-5f8279ff3e5a'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'ca8aecda-4642-45c7-96ed-309c35c4b78f'::uuid,'MARINES',NULL,true,now(),now()), + ('2051a441-f4d0-4b6e-8614-74761de505e6'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'e4bc9404-5466-4a41-993e-09474266afc3'::uuid,'MARINES',NULL,true,now(),now()), + ('6797daed-f002-431c-829b-dab7c1b16ff2'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'d4a51d90-3945-4ad3-9cba-a18d8d7b34d7'::uuid,'MARINES',NULL,true,now(),now()), + ('2398bf11-1986-4914-8e47-6afac423283a'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'a5a60d63-d9a8-4bde-9081-f011784b2d31'::uuid,'MARINES',NULL,true,now(),now()); +INSERT INTO gbloc_aors (id,jppso_regions_id,oconus_rate_area_id,department_indicator,shipment_type,is_active,created_at,updated_at) VALUES + ('f3a6c247-4c4c-4f45-9162-50307d4711f5'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'93842d74-1f3e-46cd-aca9-9f0dafbd20a1'::uuid,'MARINES',NULL,true,now(),now()), + ('0a82b196-7c24-4214-9155-05f0c5c2d7e9'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'1bc0dbda-f0ce-4b76-a551-78dbaaa9e3ec'::uuid,'MARINES',NULL,true,now(),now()), + ('af0a2db3-2e2e-4a78-804b-9a8b89b96e12'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'f1a7ef90-cfa6-4e0c-92c3-f8d70c07ba4d'::uuid,'MARINES',NULL,true,now(),now()), + ('5205a965-d424-469a-9526-17ef551685e6'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'9c5b4c4d-e05c-42ca-bd77-b61f5d8c7afc'::uuid,'MARINES',NULL,true,now(),now()), + ('f263fdb0-933b-42a7-925e-a9852c5804fa'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'27ec2576-78dd-4605-b1a8-0b9ca207fc26'::uuid,'MARINES',NULL,true,now(),now()), + ('b03c7ae3-4d6d-445c-b94a-73af723e5226'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'12396ebc-59e9-430a-8475-759a38af6b7a'::uuid,'MARINES',NULL,true,now(),now()); + + +drop view move_to_gbloc; +CREATE OR REPLACE VIEW move_to_gbloc AS +SELECT move_id, gbloc FROM ( + SELECT DISTINCT ON (sh.move_id) sh.move_id, s.affiliation, + COALESCE(pctg.gbloc, coalesce(pctg_oconus_bos.gbloc, coalesce(pctg_oconus.gbloc, pctg_ppm.gbloc))) AS gbloc + FROM mto_shipments sh + JOIN moves m ON sh.move_id = m.id + JOIN orders o on m.orders_id = o.id + JOIN service_members s on o.service_member_id = s.id + LEFT JOIN ( SELECT a.id AS address_id, + pctg_1.gbloc, pctg_1.postal_code + FROM addresses a + JOIN postal_code_to_gblocs pctg_1 ON a.postal_code::text = pctg_1.postal_code::text) pctg ON pctg.address_id = sh.pickup_address_id + LEFT JOIN ( SELECT ppm.shipment_id, + pctg_1.gbloc + FROM ppm_shipments ppm + JOIN addresses ppm_address ON ppm.pickup_postal_address_id = ppm_address.id + JOIN postal_code_to_gblocs pctg_1 ON ppm_address.postal_code::text = pctg_1.postal_code::text) pctg_ppm ON pctg_ppm.shipment_id = sh.id + LEFT JOIN ( SELECT a.id AS address_id, + cast(jr.code as varchar) AS gbloc, ga.department_indicator + FROM addresses a + JOIN re_oconus_rate_areas ora ON a.us_post_region_cities_id = ora.us_post_region_cities_id + JOIN gbloc_aors ga ON ora.id = ga.oconus_rate_area_id + JOIN jppso_regions jr ON ga.jppso_regions_id = jr.id + ) pctg_oconus_bos ON pctg_oconus_bos.address_id = sh.pickup_address_id + and case when s.affiliation = 'AIR_FORCE' THEN 'AIR_AND_SPACE_FORCE' + when s.affiliation = 'SPACE_FORCE' THEN 'AIR_AND_SPACE_FORCE' + else s.affiliation + end = pctg_oconus_bos.department_indicator + LEFT JOIN ( SELECT a.id AS address_id, + cast(pctg_1.code as varchar) AS gbloc, ga.department_indicator + FROM addresses a + JOIN re_oconus_rate_areas ora ON a.us_post_region_cities_id = ora.us_post_region_cities_id + JOIN gbloc_aors ga ON ora.id = ga.oconus_rate_area_id + JOIN jppso_regions pctg_1 ON ga.jppso_regions_id = pctg_1.id + ) pctg_oconus ON pctg_oconus.address_id = sh.pickup_address_id and pctg_oconus.department_indicator is null + WHERE sh.deleted_at IS NULL + ORDER BY sh.move_id, sh.created_at) as m; + + +-- used for the destination queue +CREATE OR REPLACE VIEW move_to_dest_gbloc +AS +SELECT distinct move_id, gbloc FROM ( + SELECT sh.move_id, s.affiliation, + COALESCE(case when s.affiliation = 'MARINES' then 'USMC' else pctg.gbloc end, coalesce(pctg_oconus_bos.gbloc, coalesce(pctg_oconus.gbloc, pctg_ppm.gbloc))) AS gbloc + FROM mto_shipments sh + JOIN moves m ON sh.move_id = m.id + JOIN orders o on m.orders_id = o.id + JOIN service_members s on o.service_member_id = s.id + LEFT JOIN ( SELECT a.id AS address_id, + pctg_1.gbloc, pctg_1.postal_code + FROM addresses a + JOIN postal_code_to_gblocs pctg_1 ON a.postal_code::text = pctg_1.postal_code::text) pctg ON pctg.address_id = sh.destination_address_id + LEFT JOIN ( SELECT ppm.shipment_id, + pctg_1.gbloc + FROM ppm_shipments ppm + JOIN addresses ppm_address ON ppm.destination_postal_address_id = ppm_address.id + JOIN postal_code_to_gblocs pctg_1 ON ppm_address.postal_code::text = pctg_1.postal_code::text) pctg_ppm ON pctg_ppm.shipment_id = sh.id + LEFT JOIN ( SELECT a.id AS address_id, + cast(jr.code as varchar) AS gbloc, ga.department_indicator + FROM addresses a + JOIN re_oconus_rate_areas ora ON a.us_post_region_cities_id = ora.us_post_region_cities_id + JOIN gbloc_aors ga ON ora.id = ga.oconus_rate_area_id + JOIN jppso_regions jr ON ga.jppso_regions_id = jr.id + ) pctg_oconus_bos ON pctg_oconus_bos.address_id = sh.destination_address_id + and case when s.affiliation = 'AIR_FORCE' THEN 'AIR_AND_SPACE_FORCE' + when s.affiliation = 'SPACE_FORCE' THEN 'AIR_AND_SPACE_FORCE' + else s.affiliation + end = pctg_oconus_bos.department_indicator + LEFT JOIN ( SELECT a.id AS address_id, + cast(pctg_1.code as varchar) AS gbloc, ga.department_indicator + FROM addresses a + JOIN re_oconus_rate_areas ora ON a.us_post_region_cities_id = ora.us_post_region_cities_id + JOIN gbloc_aors ga ON ora.id = ga.oconus_rate_area_id + JOIN jppso_regions pctg_1 ON ga.jppso_regions_id = pctg_1.id + ) pctg_oconus ON pctg_oconus.address_id = sh.destination_address_id and pctg_oconus.department_indicator is null + WHERE sh.deleted_at IS NULL) as m; + +-- database function that returns a list of moves that have destination requests +-- this includes shipment address update requests, destination SIT, & destination shuttle +CREATE OR REPLACE FUNCTION get_destination_queue( + user_gbloc TEXT DEFAULT NULL, + customer_name TEXT DEFAULT NULL, + edipi TEXT DEFAULT NULL, + emplid TEXT DEFAULT NULL, + m_status TEXT[] DEFAULT NULL, + move_code TEXT DEFAULT NULL, + requested_move_date TIMESTAMP DEFAULT NULL, + date_submitted TIMESTAMP DEFAULT NULL, + branch TEXT DEFAULT NULL, + origin_duty_location TEXT DEFAULT NULL, + counseling_office TEXT DEFAULT NULL, + too_assigned_user TEXT DEFAULT NULL, + page INTEGER DEFAULT 1, + per_page INTEGER DEFAULT 20, + sort TEXT DEFAULT NULL, + sort_direction TEXT DEFAULT NULL +) +RETURNS TABLE ( + id UUID, + show BOOLEAN, + locator TEXT, + submitted_at TIMESTAMP WITH TIME ZONE, + orders_id UUID, + status TEXT, + locked_by UUID, + too_assigned_id UUID, + counseling_transportation_office_id UUID, + orders JSONB, + mto_shipments JSONB, + counseling_transportation_office JSONB, + too_assigned JSONB, + total_count BIGINT +) AS $$ +DECLARE + sql_query TEXT; + offset_value INTEGER; + sort_column TEXT; + sort_order TEXT; +BEGIN + IF page < 1 THEN + page := 1; + END IF; + + IF per_page < 1 THEN + per_page := 20; + END IF; + + -- OFFSET for pagination + offset_value := (page - 1) * per_page; + + sql_query := ' + SELECT + moves.id AS id, + moves.show AS show, + moves.locator::TEXT AS locator, + moves.submitted_at::TIMESTAMP WITH TIME ZONE AS submitted_at, + moves.orders_id AS orders_id, + moves.status::TEXT AS status, + moves.locked_by AS locked_by, + moves.too_assigned_id AS too_assigned_id, + moves.counseling_transportation_office_id AS counseling_transportation_office_id, + json_build_object( + ''id'', orders.id, + ''origin_duty_location_gbloc'', orders.gbloc, + ''service_member'', json_build_object( + ''id'', service_members.id, + ''first_name'', service_members.first_name, + ''last_name'', service_members.last_name, + ''edipi'', service_members.edipi, + ''emplid'', service_members.emplid, + ''affiliation'', service_members.affiliation + ), + ''origin_duty_location'', json_build_object( + ''name'', origin_duty_locations.name + ) + )::JSONB AS orders, + COALESCE( + ( + SELECT json_agg( + json_build_object( + ''id'', ms.id, + ''shipment_type'', ms.shipment_type, + ''status'', ms.status, + ''requested_pickup_date'', TO_CHAR(ms.requested_pickup_date, ''YYYY-MM-DD"T00:00:00Z"''), + ''scheduled_pickup_date'', TO_CHAR(ms.scheduled_pickup_date, ''YYYY-MM-DD"T00:00:00Z"''), + ''approved_date'', TO_CHAR(ms.approved_date, ''YYYY-MM-DD"T00:00:00Z"''), + ''prime_estimated_weight'', ms.prime_estimated_weight + ) + ) + FROM ( + SELECT DISTINCT ON (mto_shipments.id) mto_shipments.* + FROM mto_shipments + WHERE mto_shipments.move_id = moves.id + ) AS ms + ), + ''[]'' + )::JSONB AS mto_shipments, + json_build_object( + ''name'', counseling_offices.name + )::JSONB AS counseling_transportation_office, + json_build_object( + ''first_name'', too_user.first_name, + ''last_name'', too_user.last_name + )::JSONB AS too_assigned, + COUNT(*) OVER() AS total_count + FROM moves + JOIN orders ON moves.orders_id = orders.id + JOIN mto_shipments ON mto_shipments.move_id = moves.id + LEFT JOIN ppm_shipments ON ppm_shipments.shipment_id = mto_shipments.id + JOIN mto_service_items ON mto_shipments.id = mto_service_items.mto_shipment_id + JOIN re_services ON mto_service_items.re_service_id = re_services.id + JOIN service_members ON orders.service_member_id = service_members.id + JOIN duty_locations AS new_duty_locations ON orders.new_duty_location_id = new_duty_locations.id + JOIN duty_locations AS origin_duty_locations ON orders.origin_duty_location_id = origin_duty_locations.id + LEFT JOIN office_users AS too_user ON moves.too_assigned_id = too_user.id + LEFT JOIN office_users AS locked_user ON moves.locked_by = locked_user.id + LEFT JOIN transportation_offices AS counseling_offices + ON moves.counseling_transportation_office_id = counseling_offices.id + LEFT JOIN shipment_address_updates ON shipment_address_updates.shipment_id = mto_shipments.id + JOIN move_to_dest_gbloc ON move_to_dest_gbloc.move_id = moves.id + WHERE moves.show = TRUE + '; + + IF user_gbloc IS NOT NULL THEN + sql_query := sql_query || ' AND move_to_dest_gbloc.gbloc = $1 '; + END IF; + + IF customer_name IS NOT NULL THEN + sql_query := sql_query || ' AND ( + service_members.first_name || '' '' || service_members.last_name ILIKE ''%'' || $2 || ''%'' + OR service_members.last_name || '' '' || service_members.first_name ILIKE ''%'' || $2 || ''%'' + )'; + END IF; + + IF edipi IS NOT NULL THEN + sql_query := sql_query || ' AND service_members.edipi ILIKE ''%'' || $3 || ''%'' '; + END IF; + + IF emplid IS NOT NULL THEN + sql_query := sql_query || ' AND service_members.emplid ILIKE ''%'' || $4 || ''%'' '; + END IF; + + IF m_status IS NOT NULL THEN + sql_query := sql_query || ' AND moves.status = ANY($5) '; + END IF; + + IF move_code IS NOT NULL THEN + sql_query := sql_query || ' AND moves.locator ILIKE ''%'' || $6 || ''%'' '; + END IF; + + IF requested_move_date IS NOT NULL THEN + sql_query := sql_query || ' AND ( + mto_shipments.requested_pickup_date::DATE = $7::DATE + OR ppm_shipments.expected_departure_date::DATE = $7::DATE + OR (mto_shipments.shipment_type = ''HHG_OUTOF_NTS'' AND mto_shipments.requested_delivery_date::DATE = $7::DATE) + )'; + END IF; + + IF date_submitted IS NOT NULL THEN + sql_query := sql_query || ' AND moves.submitted_at::DATE = $8::DATE '; + END IF; + + IF branch IS NOT NULL THEN + sql_query := sql_query || ' AND service_members.affiliation ILIKE ''%'' || $9 || ''%'' '; + END IF; + + IF origin_duty_location IS NOT NULL THEN + sql_query := sql_query || ' AND origin_duty_locations.name ILIKE ''%'' || $10 || ''%'' '; + END IF; + + IF counseling_office IS NOT NULL THEN + sql_query := sql_query || ' AND counseling_offices.name ILIKE ''%'' || $11 || ''%'' '; + END IF; + + IF too_assigned_user IS NOT NULL THEN + sql_query := sql_query || ' AND (too_user.first_name || '' '' || too_user.last_name) ILIKE ''%'' || $12 || ''%'' '; + END IF; + + -- add destination queue-specific filters (pending dest address requests, dest SIT & dest shuttle service items) + sql_query := sql_query || ' + AND ( + shipment_address_updates.status = ''REQUESTED'' + OR ( + mto_service_items.status = ''SUBMITTED'' + AND re_services.code IN (''DDFSIT'', ''DDASIT'', ''DDDSIT'', ''DDSHUT'', ''DDSFSC'', ''IDFSIT'', ''IDASIT'', ''IDDSIT'', ''IDSHUT'') + ) + ) + '; + + -- default sorting values if none are provided (move.id) + sort_column := 'id'; + sort_order := 'ASC'; + + IF sort IS NOT NULL THEN + CASE sort + WHEN 'locator' THEN sort_column := 'moves.locator'; + WHEN 'status' THEN sort_column := 'moves.status'; + WHEN 'customerName' THEN sort_column := 'service_members.last_name'; + WHEN 'edipi' THEN sort_column := 'service_members.edipi'; + WHEN 'emplid' THEN sort_column := 'service_members.emplid'; + WHEN 'requestedMoveDate' THEN sort_column := 'COALESCE(mto_shipments.requested_pickup_date, ppm_shipments.expected_departure_date, mto_shipments.requested_delivery_date)'; + WHEN 'appearedInTooAt' THEN sort_column := 'COALESCE(moves.submitted_at, moves.approvals_requested_at)'; + WHEN 'branch' THEN sort_column := 'service_members.affiliation'; + WHEN 'originDutyLocation' THEN sort_column := 'origin_duty_locations.name'; + WHEN 'counselingOffice' THEN sort_column := 'counseling_offices.name'; + WHEN 'assignedTo' THEN sort_column := 'too_user.last_name'; + ELSE + sort_column := 'moves.id'; + END CASE; + END IF; + + IF sort_direction IS NOT NULL THEN + IF LOWER(sort_direction) = 'desc' THEN + sort_order := 'DESC'; + ELSE + sort_order := 'ASC'; + END IF; + END IF; + + sql_query := sql_query || ' + GROUP BY + moves.id, + moves.show, + moves.locator, + moves.submitted_at, + moves.orders_id, + moves.status, + moves.locked_by, + moves.too_assigned_id, + moves.counseling_transportation_office_id, + mto_shipments.requested_pickup_date, + mto_shipments.requested_delivery_date, + ppm_shipments.expected_departure_date, + orders.id, + service_members.id, + service_members.first_name, + service_members.last_name, + service_members.edipi, + service_members.emplid, + service_members.affiliation, + origin_duty_locations.name, + counseling_offices.name, + too_user.first_name, + too_user.last_name'; + sql_query := sql_query || format(' ORDER BY %s %s ', sort_column, sort_order); + sql_query := sql_query || ' LIMIT $13 OFFSET $14 '; + + RETURN QUERY EXECUTE sql_query + USING user_gbloc, customer_name, edipi, emplid, m_status, move_code, requested_move_date, date_submitted, + branch, origin_duty_location, counseling_office, too_assigned_user, per_page, offset_value; + +END; +$$ LANGUAGE plpgsql; diff --git a/pkg/gen/ghcapi/configure_mymove.go b/pkg/gen/ghcapi/configure_mymove.go index 32eb5174c09..08d71eb7034 100644 --- a/pkg/gen/ghcapi/configure_mymove.go +++ b/pkg/gen/ghcapi/configure_mymove.go @@ -242,6 +242,11 @@ func configureAPI(api *ghcoperations.MymoveAPI) http.Handler { return middleware.NotImplemented("operation customer_support_remarks.GetCustomerSupportRemarksForMove has not yet been implemented") }) } + if api.QueuesGetDestinationRequestsQueueHandler == nil { + api.QueuesGetDestinationRequestsQueueHandler = queues.GetDestinationRequestsQueueHandlerFunc(func(params queues.GetDestinationRequestsQueueParams) middleware.Responder { + return middleware.NotImplemented("operation queues.GetDestinationRequestsQueue has not yet been implemented") + }) + } if api.GhcDocumentsGetDocumentHandler == nil { api.GhcDocumentsGetDocumentHandler = ghc_documents.GetDocumentHandlerFunc(func(params ghc_documents.GetDocumentParams) middleware.Responder { return middleware.NotImplemented("operation ghc_documents.GetDocument has not yet been implemented") diff --git a/pkg/gen/ghcapi/embedded_spec.go b/pkg/gen/ghcapi/embedded_spec.go index d12300d9fad..0704324506f 100644 --- a/pkg/gen/ghcapi/embedded_spec.go +++ b/pkg/gen/ghcapi/embedded_spec.go @@ -4676,6 +4676,156 @@ func init() { } } }, + "/queues/destination-requests": { + "get": { + "description": "A TOO will view this queue when they have destination requests tied to their GBLOC. This includes unapproved destination SIT service items, destination shuttle service items and destination address requests that are not yet approved by the TOO.\n", + "produces": [ + "application/json" + ], + "tags": [ + "queues" + ], + "summary": "Gets queued list of all customer moves by GBLOC that have both CONUS \u0026 OCONUS destination requests (destination SIT, destination shuttle, address requests)", + "operationId": "getDestinationRequestsQueue", + "parameters": [ + { + "type": "integer", + "description": "requested page of results", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "results per page", + "name": "perPage", + "in": "query" + }, + { + "enum": [ + "customerName", + "edipi", + "emplid", + "branch", + "locator", + "status", + "originDutyLocation", + "destinationDutyLocation", + "requestedMoveDate", + "appearedInTooAt", + "assignedTo", + "counselingOffice" + ], + "type": "string", + "description": "field that results should be sorted by", + "name": "sort", + "in": "query" + }, + { + "enum": [ + "asc", + "desc" + ], + "type": "string", + "description": "direction of sort order if applied", + "name": "order", + "in": "query" + }, + { + "type": "string", + "name": "branch", + "in": "query" + }, + { + "type": "string", + "name": "locator", + "in": "query" + }, + { + "type": "string", + "name": "customerName", + "in": "query" + }, + { + "type": "string", + "name": "edipi", + "in": "query" + }, + { + "type": "string", + "name": "emplid", + "in": "query" + }, + { + "uniqueItems": true, + "type": "array", + "items": { + "type": "string" + }, + "collectionFormat": "multi", + "name": "originDutyLocation", + "in": "query" + }, + { + "type": "string", + "name": "destinationDutyLocation", + "in": "query" + }, + { + "type": "string", + "format": "date-time", + "name": "appearedInTooAt", + "in": "query" + }, + { + "type": "string", + "description": "filters the requested pickup date of a shipment on the move", + "name": "requestedMoveDate", + "in": "query" + }, + { + "uniqueItems": true, + "type": "array", + "items": { + "enum": [ + "SUBMITTED", + "SERVICE COUNSELING COMPLETED", + "APPROVALS REQUESTED" + ], + "type": "string" + }, + "description": "Filtering for the status.", + "name": "status", + "in": "query" + }, + { + "type": "string", + "description": "Used to illustrate which user is assigned to this move.\n", + "name": "assignedTo", + "in": "query" + }, + { + "type": "string", + "description": "filters using a counselingOffice name of the move", + "name": "counselingOffice", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successfully returned all moves matching the criteria", + "schema": { + "$ref": "#/definitions/QueueMovesResult" + } + }, + "403": { + "$ref": "#/responses/PermissionDenied" + }, + "500": { + "$ref": "#/responses/ServerError" + } + } + } + }, "/queues/moves": { "get": { "description": "An office TOO user will be assigned a transportation office that will determine which moves are displayed in their queue based on the origin duty location. GHC moves will show up here onced they have reached the submitted status sent by the customer and have move task orders, shipments, and service items to approve.\n", @@ -21342,6 +21492,162 @@ func init() { } } }, + "/queues/destination-requests": { + "get": { + "description": "A TOO will view this queue when they have destination requests tied to their GBLOC. This includes unapproved destination SIT service items, destination shuttle service items and destination address requests that are not yet approved by the TOO.\n", + "produces": [ + "application/json" + ], + "tags": [ + "queues" + ], + "summary": "Gets queued list of all customer moves by GBLOC that have both CONUS \u0026 OCONUS destination requests (destination SIT, destination shuttle, address requests)", + "operationId": "getDestinationRequestsQueue", + "parameters": [ + { + "type": "integer", + "description": "requested page of results", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "results per page", + "name": "perPage", + "in": "query" + }, + { + "enum": [ + "customerName", + "edipi", + "emplid", + "branch", + "locator", + "status", + "originDutyLocation", + "destinationDutyLocation", + "requestedMoveDate", + "appearedInTooAt", + "assignedTo", + "counselingOffice" + ], + "type": "string", + "description": "field that results should be sorted by", + "name": "sort", + "in": "query" + }, + { + "enum": [ + "asc", + "desc" + ], + "type": "string", + "description": "direction of sort order if applied", + "name": "order", + "in": "query" + }, + { + "type": "string", + "name": "branch", + "in": "query" + }, + { + "type": "string", + "name": "locator", + "in": "query" + }, + { + "type": "string", + "name": "customerName", + "in": "query" + }, + { + "type": "string", + "name": "edipi", + "in": "query" + }, + { + "type": "string", + "name": "emplid", + "in": "query" + }, + { + "uniqueItems": true, + "type": "array", + "items": { + "type": "string" + }, + "collectionFormat": "multi", + "name": "originDutyLocation", + "in": "query" + }, + { + "type": "string", + "name": "destinationDutyLocation", + "in": "query" + }, + { + "type": "string", + "format": "date-time", + "name": "appearedInTooAt", + "in": "query" + }, + { + "type": "string", + "description": "filters the requested pickup date of a shipment on the move", + "name": "requestedMoveDate", + "in": "query" + }, + { + "uniqueItems": true, + "type": "array", + "items": { + "enum": [ + "SUBMITTED", + "SERVICE COUNSELING COMPLETED", + "APPROVALS REQUESTED" + ], + "type": "string" + }, + "description": "Filtering for the status.", + "name": "status", + "in": "query" + }, + { + "type": "string", + "description": "Used to illustrate which user is assigned to this move.\n", + "name": "assignedTo", + "in": "query" + }, + { + "type": "string", + "description": "filters using a counselingOffice name of the move", + "name": "counselingOffice", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successfully returned all moves matching the criteria", + "schema": { + "$ref": "#/definitions/QueueMovesResult" + } + }, + "403": { + "description": "The request was denied", + "schema": { + "$ref": "#/definitions/Error" + } + }, + "500": { + "description": "A server error occurred", + "schema": { + "$ref": "#/definitions/Error" + } + } + } + } + }, "/queues/moves": { "get": { "description": "An office TOO user will be assigned a transportation office that will determine which moves are displayed in their queue based on the origin duty location. GHC moves will show up here onced they have reached the submitted status sent by the customer and have move task orders, shipments, and service items to approve.\n", diff --git a/pkg/gen/ghcapi/ghcoperations/mymove_api.go b/pkg/gen/ghcapi/ghcoperations/mymove_api.go index c53c0fec4d7..61bda14b7d3 100644 --- a/pkg/gen/ghcapi/ghcoperations/mymove_api.go +++ b/pkg/gen/ghcapi/ghcoperations/mymove_api.go @@ -173,6 +173,9 @@ func NewMymoveAPI(spec *loads.Document) *MymoveAPI { CustomerSupportRemarksGetCustomerSupportRemarksForMoveHandler: customer_support_remarks.GetCustomerSupportRemarksForMoveHandlerFunc(func(params customer_support_remarks.GetCustomerSupportRemarksForMoveParams) middleware.Responder { return middleware.NotImplemented("operation customer_support_remarks.GetCustomerSupportRemarksForMove has not yet been implemented") }), + QueuesGetDestinationRequestsQueueHandler: queues.GetDestinationRequestsQueueHandlerFunc(func(params queues.GetDestinationRequestsQueueParams) middleware.Responder { + return middleware.NotImplemented("operation queues.GetDestinationRequestsQueue has not yet been implemented") + }), GhcDocumentsGetDocumentHandler: ghc_documents.GetDocumentHandlerFunc(func(params ghc_documents.GetDocumentParams) middleware.Responder { return middleware.NotImplemented("operation ghc_documents.GetDocument has not yet been implemented") }), @@ -509,6 +512,8 @@ type MymoveAPI struct { CustomerGetCustomerHandler customer.GetCustomerHandler // CustomerSupportRemarksGetCustomerSupportRemarksForMoveHandler sets the operation handler for the get customer support remarks for move operation CustomerSupportRemarksGetCustomerSupportRemarksForMoveHandler customer_support_remarks.GetCustomerSupportRemarksForMoveHandler + // QueuesGetDestinationRequestsQueueHandler sets the operation handler for the get destination requests queue operation + QueuesGetDestinationRequestsQueueHandler queues.GetDestinationRequestsQueueHandler // GhcDocumentsGetDocumentHandler sets the operation handler for the get document operation GhcDocumentsGetDocumentHandler ghc_documents.GetDocumentHandler // MoveTaskOrderGetEntitlementsHandler sets the operation handler for the get entitlements operation @@ -842,6 +847,9 @@ func (o *MymoveAPI) Validate() error { if o.CustomerSupportRemarksGetCustomerSupportRemarksForMoveHandler == nil { unregistered = append(unregistered, "customer_support_remarks.GetCustomerSupportRemarksForMoveHandler") } + if o.QueuesGetDestinationRequestsQueueHandler == nil { + unregistered = append(unregistered, "queues.GetDestinationRequestsQueueHandler") + } if o.GhcDocumentsGetDocumentHandler == nil { unregistered = append(unregistered, "ghc_documents.GetDocumentHandler") } @@ -1295,6 +1303,10 @@ func (o *MymoveAPI) initHandlerCache() { if o.handlers["GET"] == nil { o.handlers["GET"] = make(map[string]http.Handler) } + o.handlers["GET"]["/queues/destination-requests"] = queues.NewGetDestinationRequestsQueue(o.context, o.QueuesGetDestinationRequestsQueueHandler) + if o.handlers["GET"] == nil { + o.handlers["GET"] = make(map[string]http.Handler) + } o.handlers["GET"]["/documents/{documentId}"] = ghc_documents.NewGetDocument(o.context, o.GhcDocumentsGetDocumentHandler) if o.handlers["GET"] == nil { o.handlers["GET"] = make(map[string]http.Handler) diff --git a/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue.go b/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue.go new file mode 100644 index 00000000000..0bc440cf200 --- /dev/null +++ b/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue.go @@ -0,0 +1,58 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package queues + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the generate command + +import ( + "net/http" + + "github.com/go-openapi/runtime/middleware" +) + +// GetDestinationRequestsQueueHandlerFunc turns a function with the right signature into a get destination requests queue handler +type GetDestinationRequestsQueueHandlerFunc func(GetDestinationRequestsQueueParams) middleware.Responder + +// Handle executing the request and returning a response +func (fn GetDestinationRequestsQueueHandlerFunc) Handle(params GetDestinationRequestsQueueParams) middleware.Responder { + return fn(params) +} + +// GetDestinationRequestsQueueHandler interface for that can handle valid get destination requests queue params +type GetDestinationRequestsQueueHandler interface { + Handle(GetDestinationRequestsQueueParams) middleware.Responder +} + +// NewGetDestinationRequestsQueue creates a new http.Handler for the get destination requests queue operation +func NewGetDestinationRequestsQueue(ctx *middleware.Context, handler GetDestinationRequestsQueueHandler) *GetDestinationRequestsQueue { + return &GetDestinationRequestsQueue{Context: ctx, Handler: handler} +} + +/* + GetDestinationRequestsQueue swagger:route GET /queues/destination-requests queues getDestinationRequestsQueue + +Gets queued list of all customer moves by GBLOC that have both CONUS & OCONUS destination requests (destination SIT, destination shuttle, address requests) + +A TOO will view this queue when they have destination requests tied to their GBLOC. This includes unapproved destination SIT service items, destination shuttle service items and destination address requests that are not yet approved by the TOO. +*/ +type GetDestinationRequestsQueue struct { + Context *middleware.Context + Handler GetDestinationRequestsQueueHandler +} + +func (o *GetDestinationRequestsQueue) ServeHTTP(rw http.ResponseWriter, r *http.Request) { + route, rCtx, _ := o.Context.RouteInfo(r) + if rCtx != nil { + *r = *rCtx + } + var Params = NewGetDestinationRequestsQueueParams() + if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params + o.Context.Respond(rw, r, route.Produces, route, err) + return + } + + res := o.Handler.Handle(Params) // actually handle the request + o.Context.Respond(rw, r, route.Produces, route, res) + +} diff --git a/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue_parameters.go b/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue_parameters.go new file mode 100644 index 00000000000..dac60111a5d --- /dev/null +++ b/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue_parameters.go @@ -0,0 +1,589 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package queues + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "fmt" + "net/http" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/runtime/middleware" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// NewGetDestinationRequestsQueueParams creates a new GetDestinationRequestsQueueParams object +// +// There are no default values defined in the spec. +func NewGetDestinationRequestsQueueParams() GetDestinationRequestsQueueParams { + + return GetDestinationRequestsQueueParams{} +} + +// GetDestinationRequestsQueueParams contains all the bound params for the get destination requests queue operation +// typically these are obtained from a http.Request +// +// swagger:parameters getDestinationRequestsQueue +type GetDestinationRequestsQueueParams struct { + + // HTTP Request Object + HTTPRequest *http.Request `json:"-"` + + /* + In: query + */ + AppearedInTooAt *strfmt.DateTime + /*Used to illustrate which user is assigned to this move. + + In: query + */ + AssignedTo *string + /* + In: query + */ + Branch *string + /*filters using a counselingOffice name of the move + In: query + */ + CounselingOffice *string + /* + In: query + */ + CustomerName *string + /* + In: query + */ + DestinationDutyLocation *string + /* + In: query + */ + Edipi *string + /* + In: query + */ + Emplid *string + /* + In: query + */ + Locator *string + /*direction of sort order if applied + In: query + */ + Order *string + /* + Unique: true + In: query + Collection Format: multi + */ + OriginDutyLocation []string + /*requested page of results + In: query + */ + Page *int64 + /*results per page + In: query + */ + PerPage *int64 + /*filters the requested pickup date of a shipment on the move + In: query + */ + RequestedMoveDate *string + /*field that results should be sorted by + In: query + */ + Sort *string + /*Filtering for the status. + Unique: true + In: query + */ + Status []string +} + +// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface +// for simple values it will use straight method calls. +// +// To ensure default values, the struct must have been initialized with NewGetDestinationRequestsQueueParams() beforehand. +func (o *GetDestinationRequestsQueueParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error { + var res []error + + o.HTTPRequest = r + + qs := runtime.Values(r.URL.Query()) + + qAppearedInTooAt, qhkAppearedInTooAt, _ := qs.GetOK("appearedInTooAt") + if err := o.bindAppearedInTooAt(qAppearedInTooAt, qhkAppearedInTooAt, route.Formats); err != nil { + res = append(res, err) + } + + qAssignedTo, qhkAssignedTo, _ := qs.GetOK("assignedTo") + if err := o.bindAssignedTo(qAssignedTo, qhkAssignedTo, route.Formats); err != nil { + res = append(res, err) + } + + qBranch, qhkBranch, _ := qs.GetOK("branch") + if err := o.bindBranch(qBranch, qhkBranch, route.Formats); err != nil { + res = append(res, err) + } + + qCounselingOffice, qhkCounselingOffice, _ := qs.GetOK("counselingOffice") + if err := o.bindCounselingOffice(qCounselingOffice, qhkCounselingOffice, route.Formats); err != nil { + res = append(res, err) + } + + qCustomerName, qhkCustomerName, _ := qs.GetOK("customerName") + if err := o.bindCustomerName(qCustomerName, qhkCustomerName, route.Formats); err != nil { + res = append(res, err) + } + + qDestinationDutyLocation, qhkDestinationDutyLocation, _ := qs.GetOK("destinationDutyLocation") + if err := o.bindDestinationDutyLocation(qDestinationDutyLocation, qhkDestinationDutyLocation, route.Formats); err != nil { + res = append(res, err) + } + + qEdipi, qhkEdipi, _ := qs.GetOK("edipi") + if err := o.bindEdipi(qEdipi, qhkEdipi, route.Formats); err != nil { + res = append(res, err) + } + + qEmplid, qhkEmplid, _ := qs.GetOK("emplid") + if err := o.bindEmplid(qEmplid, qhkEmplid, route.Formats); err != nil { + res = append(res, err) + } + + qLocator, qhkLocator, _ := qs.GetOK("locator") + if err := o.bindLocator(qLocator, qhkLocator, route.Formats); err != nil { + res = append(res, err) + } + + qOrder, qhkOrder, _ := qs.GetOK("order") + if err := o.bindOrder(qOrder, qhkOrder, route.Formats); err != nil { + res = append(res, err) + } + + qOriginDutyLocation, qhkOriginDutyLocation, _ := qs.GetOK("originDutyLocation") + if err := o.bindOriginDutyLocation(qOriginDutyLocation, qhkOriginDutyLocation, route.Formats); err != nil { + res = append(res, err) + } + + qPage, qhkPage, _ := qs.GetOK("page") + if err := o.bindPage(qPage, qhkPage, route.Formats); err != nil { + res = append(res, err) + } + + qPerPage, qhkPerPage, _ := qs.GetOK("perPage") + if err := o.bindPerPage(qPerPage, qhkPerPage, route.Formats); err != nil { + res = append(res, err) + } + + qRequestedMoveDate, qhkRequestedMoveDate, _ := qs.GetOK("requestedMoveDate") + if err := o.bindRequestedMoveDate(qRequestedMoveDate, qhkRequestedMoveDate, route.Formats); err != nil { + res = append(res, err) + } + + qSort, qhkSort, _ := qs.GetOK("sort") + if err := o.bindSort(qSort, qhkSort, route.Formats); err != nil { + res = append(res, err) + } + + qStatus, qhkStatus, _ := qs.GetOK("status") + if err := o.bindStatus(qStatus, qhkStatus, route.Formats); err != nil { + res = append(res, err) + } + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +// bindAppearedInTooAt binds and validates parameter AppearedInTooAt from query. +func (o *GetDestinationRequestsQueueParams) bindAppearedInTooAt(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: false + // AllowEmptyValue: false + + if raw == "" { // empty values pass all other validations + return nil + } + + // Format: date-time + value, err := formats.Parse("date-time", raw) + if err != nil { + return errors.InvalidType("appearedInTooAt", "query", "strfmt.DateTime", raw) + } + o.AppearedInTooAt = (value.(*strfmt.DateTime)) + + if err := o.validateAppearedInTooAt(formats); err != nil { + return err + } + + return nil +} + +// validateAppearedInTooAt carries on validations for parameter AppearedInTooAt +func (o *GetDestinationRequestsQueueParams) validateAppearedInTooAt(formats strfmt.Registry) error { + + if err := validate.FormatOf("appearedInTooAt", "query", "date-time", o.AppearedInTooAt.String(), formats); err != nil { + return err + } + return nil +} + +// bindAssignedTo binds and validates parameter AssignedTo from query. +func (o *GetDestinationRequestsQueueParams) bindAssignedTo(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: false + // AllowEmptyValue: false + + if raw == "" { // empty values pass all other validations + return nil + } + o.AssignedTo = &raw + + return nil +} + +// bindBranch binds and validates parameter Branch from query. +func (o *GetDestinationRequestsQueueParams) bindBranch(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: false + // AllowEmptyValue: false + + if raw == "" { // empty values pass all other validations + return nil + } + o.Branch = &raw + + return nil +} + +// bindCounselingOffice binds and validates parameter CounselingOffice from query. +func (o *GetDestinationRequestsQueueParams) bindCounselingOffice(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: false + // AllowEmptyValue: false + + if raw == "" { // empty values pass all other validations + return nil + } + o.CounselingOffice = &raw + + return nil +} + +// bindCustomerName binds and validates parameter CustomerName from query. +func (o *GetDestinationRequestsQueueParams) bindCustomerName(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: false + // AllowEmptyValue: false + + if raw == "" { // empty values pass all other validations + return nil + } + o.CustomerName = &raw + + return nil +} + +// bindDestinationDutyLocation binds and validates parameter DestinationDutyLocation from query. +func (o *GetDestinationRequestsQueueParams) bindDestinationDutyLocation(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: false + // AllowEmptyValue: false + + if raw == "" { // empty values pass all other validations + return nil + } + o.DestinationDutyLocation = &raw + + return nil +} + +// bindEdipi binds and validates parameter Edipi from query. +func (o *GetDestinationRequestsQueueParams) bindEdipi(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: false + // AllowEmptyValue: false + + if raw == "" { // empty values pass all other validations + return nil + } + o.Edipi = &raw + + return nil +} + +// bindEmplid binds and validates parameter Emplid from query. +func (o *GetDestinationRequestsQueueParams) bindEmplid(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: false + // AllowEmptyValue: false + + if raw == "" { // empty values pass all other validations + return nil + } + o.Emplid = &raw + + return nil +} + +// bindLocator binds and validates parameter Locator from query. +func (o *GetDestinationRequestsQueueParams) bindLocator(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: false + // AllowEmptyValue: false + + if raw == "" { // empty values pass all other validations + return nil + } + o.Locator = &raw + + return nil +} + +// bindOrder binds and validates parameter Order from query. +func (o *GetDestinationRequestsQueueParams) bindOrder(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: false + // AllowEmptyValue: false + + if raw == "" { // empty values pass all other validations + return nil + } + o.Order = &raw + + if err := o.validateOrder(formats); err != nil { + return err + } + + return nil +} + +// validateOrder carries on validations for parameter Order +func (o *GetDestinationRequestsQueueParams) validateOrder(formats strfmt.Registry) error { + + if err := validate.EnumCase("order", "query", *o.Order, []interface{}{"asc", "desc"}, true); err != nil { + return err + } + + return nil +} + +// bindOriginDutyLocation binds and validates array parameter OriginDutyLocation from query. +// +// Arrays are parsed according to CollectionFormat: "multi" (defaults to "csv" when empty). +func (o *GetDestinationRequestsQueueParams) bindOriginDutyLocation(rawData []string, hasKey bool, formats strfmt.Registry) error { + // CollectionFormat: multi + originDutyLocationIC := rawData + if len(originDutyLocationIC) == 0 { + return nil + } + + var originDutyLocationIR []string + for _, originDutyLocationIV := range originDutyLocationIC { + originDutyLocationI := originDutyLocationIV + + originDutyLocationIR = append(originDutyLocationIR, originDutyLocationI) + } + + o.OriginDutyLocation = originDutyLocationIR + if err := o.validateOriginDutyLocation(formats); err != nil { + return err + } + + return nil +} + +// validateOriginDutyLocation carries on validations for parameter OriginDutyLocation +func (o *GetDestinationRequestsQueueParams) validateOriginDutyLocation(formats strfmt.Registry) error { + + // uniqueItems: true + if err := validate.UniqueItems("originDutyLocation", "query", o.OriginDutyLocation); err != nil { + return err + } + return nil +} + +// bindPage binds and validates parameter Page from query. +func (o *GetDestinationRequestsQueueParams) bindPage(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: false + // AllowEmptyValue: false + + if raw == "" { // empty values pass all other validations + return nil + } + + value, err := swag.ConvertInt64(raw) + if err != nil { + return errors.InvalidType("page", "query", "int64", raw) + } + o.Page = &value + + return nil +} + +// bindPerPage binds and validates parameter PerPage from query. +func (o *GetDestinationRequestsQueueParams) bindPerPage(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: false + // AllowEmptyValue: false + + if raw == "" { // empty values pass all other validations + return nil + } + + value, err := swag.ConvertInt64(raw) + if err != nil { + return errors.InvalidType("perPage", "query", "int64", raw) + } + o.PerPage = &value + + return nil +} + +// bindRequestedMoveDate binds and validates parameter RequestedMoveDate from query. +func (o *GetDestinationRequestsQueueParams) bindRequestedMoveDate(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: false + // AllowEmptyValue: false + + if raw == "" { // empty values pass all other validations + return nil + } + o.RequestedMoveDate = &raw + + return nil +} + +// bindSort binds and validates parameter Sort from query. +func (o *GetDestinationRequestsQueueParams) bindSort(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: false + // AllowEmptyValue: false + + if raw == "" { // empty values pass all other validations + return nil + } + o.Sort = &raw + + if err := o.validateSort(formats); err != nil { + return err + } + + return nil +} + +// validateSort carries on validations for parameter Sort +func (o *GetDestinationRequestsQueueParams) validateSort(formats strfmt.Registry) error { + + if err := validate.EnumCase("sort", "query", *o.Sort, []interface{}{"customerName", "edipi", "emplid", "branch", "locator", "status", "originDutyLocation", "destinationDutyLocation", "requestedMoveDate", "appearedInTooAt", "assignedTo", "counselingOffice"}, true); err != nil { + return err + } + + return nil +} + +// bindStatus binds and validates array parameter Status from query. +// +// Arrays are parsed according to CollectionFormat: "" (defaults to "csv" when empty). +func (o *GetDestinationRequestsQueueParams) bindStatus(rawData []string, hasKey bool, formats strfmt.Registry) error { + var qvStatus string + if len(rawData) > 0 { + qvStatus = rawData[len(rawData)-1] + } + + // CollectionFormat: + statusIC := swag.SplitByFormat(qvStatus, "") + if len(statusIC) == 0 { + return nil + } + + var statusIR []string + for i, statusIV := range statusIC { + statusI := statusIV + + if err := validate.EnumCase(fmt.Sprintf("%s.%v", "status", i), "query", statusI, []interface{}{"SUBMITTED", "SERVICE COUNSELING COMPLETED", "APPROVALS REQUESTED"}, true); err != nil { + return err + } + + statusIR = append(statusIR, statusI) + } + + o.Status = statusIR + if err := o.validateStatus(formats); err != nil { + return err + } + + return nil +} + +// validateStatus carries on validations for parameter Status +func (o *GetDestinationRequestsQueueParams) validateStatus(formats strfmt.Registry) error { + + // uniqueItems: true + if err := validate.UniqueItems("status", "query", o.Status); err != nil { + return err + } + return nil +} diff --git a/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue_responses.go b/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue_responses.go new file mode 100644 index 00000000000..ea27ea91263 --- /dev/null +++ b/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue_responses.go @@ -0,0 +1,149 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package queues + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "net/http" + + "github.com/go-openapi/runtime" + + "github.com/transcom/mymove/pkg/gen/ghcmessages" +) + +// GetDestinationRequestsQueueOKCode is the HTTP code returned for type GetDestinationRequestsQueueOK +const GetDestinationRequestsQueueOKCode int = 200 + +/* +GetDestinationRequestsQueueOK Successfully returned all moves matching the criteria + +swagger:response getDestinationRequestsQueueOK +*/ +type GetDestinationRequestsQueueOK struct { + + /* + In: Body + */ + Payload *ghcmessages.QueueMovesResult `json:"body,omitempty"` +} + +// NewGetDestinationRequestsQueueOK creates GetDestinationRequestsQueueOK with default headers values +func NewGetDestinationRequestsQueueOK() *GetDestinationRequestsQueueOK { + + return &GetDestinationRequestsQueueOK{} +} + +// WithPayload adds the payload to the get destination requests queue o k response +func (o *GetDestinationRequestsQueueOK) WithPayload(payload *ghcmessages.QueueMovesResult) *GetDestinationRequestsQueueOK { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the get destination requests queue o k response +func (o *GetDestinationRequestsQueueOK) SetPayload(payload *ghcmessages.QueueMovesResult) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *GetDestinationRequestsQueueOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(200) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} + +// GetDestinationRequestsQueueForbiddenCode is the HTTP code returned for type GetDestinationRequestsQueueForbidden +const GetDestinationRequestsQueueForbiddenCode int = 403 + +/* +GetDestinationRequestsQueueForbidden The request was denied + +swagger:response getDestinationRequestsQueueForbidden +*/ +type GetDestinationRequestsQueueForbidden struct { + + /* + In: Body + */ + Payload *ghcmessages.Error `json:"body,omitempty"` +} + +// NewGetDestinationRequestsQueueForbidden creates GetDestinationRequestsQueueForbidden with default headers values +func NewGetDestinationRequestsQueueForbidden() *GetDestinationRequestsQueueForbidden { + + return &GetDestinationRequestsQueueForbidden{} +} + +// WithPayload adds the payload to the get destination requests queue forbidden response +func (o *GetDestinationRequestsQueueForbidden) WithPayload(payload *ghcmessages.Error) *GetDestinationRequestsQueueForbidden { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the get destination requests queue forbidden response +func (o *GetDestinationRequestsQueueForbidden) SetPayload(payload *ghcmessages.Error) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *GetDestinationRequestsQueueForbidden) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(403) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} + +// GetDestinationRequestsQueueInternalServerErrorCode is the HTTP code returned for type GetDestinationRequestsQueueInternalServerError +const GetDestinationRequestsQueueInternalServerErrorCode int = 500 + +/* +GetDestinationRequestsQueueInternalServerError A server error occurred + +swagger:response getDestinationRequestsQueueInternalServerError +*/ +type GetDestinationRequestsQueueInternalServerError struct { + + /* + In: Body + */ + Payload *ghcmessages.Error `json:"body,omitempty"` +} + +// NewGetDestinationRequestsQueueInternalServerError creates GetDestinationRequestsQueueInternalServerError with default headers values +func NewGetDestinationRequestsQueueInternalServerError() *GetDestinationRequestsQueueInternalServerError { + + return &GetDestinationRequestsQueueInternalServerError{} +} + +// WithPayload adds the payload to the get destination requests queue internal server error response +func (o *GetDestinationRequestsQueueInternalServerError) WithPayload(payload *ghcmessages.Error) *GetDestinationRequestsQueueInternalServerError { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the get destination requests queue internal server error response +func (o *GetDestinationRequestsQueueInternalServerError) SetPayload(payload *ghcmessages.Error) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *GetDestinationRequestsQueueInternalServerError) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(500) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue_urlbuilder.go b/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue_urlbuilder.go new file mode 100644 index 00000000000..c8b86e869dc --- /dev/null +++ b/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue_urlbuilder.go @@ -0,0 +1,256 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package queues + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the generate command + +import ( + "errors" + "net/url" + golangswaggerpaths "path" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// GetDestinationRequestsQueueURL generates an URL for the get destination requests queue operation +type GetDestinationRequestsQueueURL struct { + AppearedInTooAt *strfmt.DateTime + AssignedTo *string + Branch *string + CounselingOffice *string + CustomerName *string + DestinationDutyLocation *string + Edipi *string + Emplid *string + Locator *string + Order *string + OriginDutyLocation []string + Page *int64 + PerPage *int64 + RequestedMoveDate *string + Sort *string + Status []string + + _basePath string + // avoid unkeyed usage + _ struct{} +} + +// WithBasePath sets the base path for this url builder, only required when it's different from the +// base path specified in the swagger spec. +// When the value of the base path is an empty string +func (o *GetDestinationRequestsQueueURL) WithBasePath(bp string) *GetDestinationRequestsQueueURL { + o.SetBasePath(bp) + return o +} + +// SetBasePath sets the base path for this url builder, only required when it's different from the +// base path specified in the swagger spec. +// When the value of the base path is an empty string +func (o *GetDestinationRequestsQueueURL) SetBasePath(bp string) { + o._basePath = bp +} + +// Build a url path and query string +func (o *GetDestinationRequestsQueueURL) Build() (*url.URL, error) { + var _result url.URL + + var _path = "/queues/destination-requests" + + _basePath := o._basePath + if _basePath == "" { + _basePath = "/ghc/v1" + } + _result.Path = golangswaggerpaths.Join(_basePath, _path) + + qs := make(url.Values) + + var appearedInTooAtQ string + if o.AppearedInTooAt != nil { + appearedInTooAtQ = o.AppearedInTooAt.String() + } + if appearedInTooAtQ != "" { + qs.Set("appearedInTooAt", appearedInTooAtQ) + } + + var assignedToQ string + if o.AssignedTo != nil { + assignedToQ = *o.AssignedTo + } + if assignedToQ != "" { + qs.Set("assignedTo", assignedToQ) + } + + var branchQ string + if o.Branch != nil { + branchQ = *o.Branch + } + if branchQ != "" { + qs.Set("branch", branchQ) + } + + var counselingOfficeQ string + if o.CounselingOffice != nil { + counselingOfficeQ = *o.CounselingOffice + } + if counselingOfficeQ != "" { + qs.Set("counselingOffice", counselingOfficeQ) + } + + var customerNameQ string + if o.CustomerName != nil { + customerNameQ = *o.CustomerName + } + if customerNameQ != "" { + qs.Set("customerName", customerNameQ) + } + + var destinationDutyLocationQ string + if o.DestinationDutyLocation != nil { + destinationDutyLocationQ = *o.DestinationDutyLocation + } + if destinationDutyLocationQ != "" { + qs.Set("destinationDutyLocation", destinationDutyLocationQ) + } + + var edipiQ string + if o.Edipi != nil { + edipiQ = *o.Edipi + } + if edipiQ != "" { + qs.Set("edipi", edipiQ) + } + + var emplidQ string + if o.Emplid != nil { + emplidQ = *o.Emplid + } + if emplidQ != "" { + qs.Set("emplid", emplidQ) + } + + var locatorQ string + if o.Locator != nil { + locatorQ = *o.Locator + } + if locatorQ != "" { + qs.Set("locator", locatorQ) + } + + var orderQ string + if o.Order != nil { + orderQ = *o.Order + } + if orderQ != "" { + qs.Set("order", orderQ) + } + + var originDutyLocationIR []string + for _, originDutyLocationI := range o.OriginDutyLocation { + originDutyLocationIS := originDutyLocationI + if originDutyLocationIS != "" { + originDutyLocationIR = append(originDutyLocationIR, originDutyLocationIS) + } + } + + originDutyLocation := swag.JoinByFormat(originDutyLocationIR, "multi") + + for _, qsv := range originDutyLocation { + qs.Add("originDutyLocation", qsv) + } + + var pageQ string + if o.Page != nil { + pageQ = swag.FormatInt64(*o.Page) + } + if pageQ != "" { + qs.Set("page", pageQ) + } + + var perPageQ string + if o.PerPage != nil { + perPageQ = swag.FormatInt64(*o.PerPage) + } + if perPageQ != "" { + qs.Set("perPage", perPageQ) + } + + var requestedMoveDateQ string + if o.RequestedMoveDate != nil { + requestedMoveDateQ = *o.RequestedMoveDate + } + if requestedMoveDateQ != "" { + qs.Set("requestedMoveDate", requestedMoveDateQ) + } + + var sortQ string + if o.Sort != nil { + sortQ = *o.Sort + } + if sortQ != "" { + qs.Set("sort", sortQ) + } + + var statusIR []string + for _, statusI := range o.Status { + statusIS := statusI + if statusIS != "" { + statusIR = append(statusIR, statusIS) + } + } + + status := swag.JoinByFormat(statusIR, "") + + if len(status) > 0 { + qsv := status[0] + if qsv != "" { + qs.Set("status", qsv) + } + } + + _result.RawQuery = qs.Encode() + + return &_result, nil +} + +// Must is a helper function to panic when the url builder returns an error +func (o *GetDestinationRequestsQueueURL) Must(u *url.URL, err error) *url.URL { + if err != nil { + panic(err) + } + if u == nil { + panic("url can't be nil") + } + return u +} + +// String returns the string representation of the path with query string +func (o *GetDestinationRequestsQueueURL) String() string { + return o.Must(o.Build()).String() +} + +// BuildFull builds a full url with scheme, host, path and query string +func (o *GetDestinationRequestsQueueURL) BuildFull(scheme, host string) (*url.URL, error) { + if scheme == "" { + return nil, errors.New("scheme is required for a full url on GetDestinationRequestsQueueURL") + } + if host == "" { + return nil, errors.New("host is required for a full url on GetDestinationRequestsQueueURL") + } + + base, err := o.Build() + if err != nil { + return nil, err + } + + base.Scheme = scheme + base.Host = host + return base, nil +} + +// StringFull returns the string representation of a complete url +func (o *GetDestinationRequestsQueueURL) StringFull(scheme, host string) string { + return o.Must(o.BuildFull(scheme, host)).String() +} diff --git a/pkg/handlers/ghcapi/api.go b/pkg/handlers/ghcapi/api.go index 4a6bed9c52d..b48c88402fc 100644 --- a/pkg/handlers/ghcapi/api.go +++ b/pkg/handlers/ghcapi/api.go @@ -551,6 +551,13 @@ func NewGhcAPIHandler(handlerConfig handlers.HandlerConfig) *ghcops.MymoveAPI { officeusercreator.NewOfficeUserFetcherPop(), } + ghcAPI.QueuesGetDestinationRequestsQueueHandler = GetDestinationRequestsQueueHandler{ + handlerConfig, + order.NewOrderFetcher(waf), + movelocker.NewMoveUnlocker(), + officeusercreator.NewOfficeUserFetcherPop(), + } + ghcAPI.QueuesListPrimeMovesHandler = ListPrimeMovesHandler{ handlerConfig, movetaskorder.NewMoveTaskOrderFetcher(waf), diff --git a/pkg/handlers/ghcapi/internal/payloads/model_to_payload.go b/pkg/handlers/ghcapi/internal/payloads/model_to_payload.go index 74ebbc80eca..353e2e7c11e 100644 --- a/pkg/handlers/ghcapi/internal/payloads/model_to_payload.go +++ b/pkg/handlers/ghcapi/internal/payloads/model_to_payload.go @@ -54,7 +54,7 @@ func OfficeUser(officeUser *models.OfficeUser) *ghcmessages.LockedOfficeUser { } func AssignedOfficeUser(officeUser *models.OfficeUser) *ghcmessages.AssignedOfficeUser { - if officeUser != nil { + if officeUser != nil && officeUser.FirstName != "" && officeUser.LastName != "" { payload := ghcmessages.AssignedOfficeUser{ OfficeUserID: strfmt.UUID(officeUser.ID.String()), FirstName: officeUser.FirstName, @@ -2623,9 +2623,11 @@ func SearchMoves(appCtx appcontext.AppContext, moves models.Moves) *ghcmessages. // populates the destination postal code of the move var destinationPostalCode string - destinationPostalCode, err = move.GetDestinationPostalCode(appCtx.DB()) + destinationAddress, err := move.GetDestinationAddress(appCtx.DB()) if err != nil { destinationPostalCode = "" + } else { + destinationPostalCode = destinationAddress.PostalCode } searchMoves[i] = &ghcmessages.SearchMove{ diff --git a/pkg/handlers/ghcapi/move_test.go b/pkg/handlers/ghcapi/move_test.go index 3b9fda47401..68b33148943 100644 --- a/pkg/handlers/ghcapi/move_test.go +++ b/pkg/handlers/ghcapi/move_test.go @@ -597,17 +597,17 @@ func (suite *HandlerSuite) TestSearchMovesHandler() { // Validate outgoing payload without shipment suite.NoError(payload.Validate(strfmt.Default)) - var moveDestinationPostalCode string + var moveDestinationAddress *models.Address var moveDestinationGBLOC string var err error // Get destination postal code and GBLOC based on business logic - moveDestinationPostalCode, err = move.GetDestinationPostalCode(suite.DB()) + moveDestinationAddress, err = move.GetDestinationAddress(suite.DB()) suite.NoError(err) moveDestinationGBLOC, err = move.GetDestinationGBLOC(suite.DB()) suite.NoError(err) - suite.Equal(moveDestinationPostalCode, "62225") + suite.Equal(moveDestinationAddress.PostalCode, "62225") suite.Equal(ghcmessages.GBLOC(moveDestinationGBLOC), ghcmessages.GBLOC("AGFM")) // Set Mock Search settings for move with MTO Shipment @@ -639,12 +639,12 @@ func (suite *HandlerSuite) TestSearchMovesHandler() { suite.NoError(payload.Validate(strfmt.Default)) // Get destination postal code and GBLOC based on business logic - moveDestinationPostalCode, err = moveWithShipment.GetDestinationPostalCode(suite.DB()) + moveDestinationAddress, err = moveWithShipment.GetDestinationAddress(suite.DB()) suite.NoError(err) moveDestinationGBLOC, err = moveWithShipment.GetDestinationGBLOC(suite.DB()) suite.NoError(err) - suite.Equal(moveDestinationPostalCode, "90210") + suite.Equal(moveDestinationAddress.PostalCode, "90210") suite.Equal(ghcmessages.GBLOC(moveDestinationGBLOC), ghcmessages.GBLOC("KKFA")) // Set Mock Search settings for move with PPM Shipment @@ -676,12 +676,12 @@ func (suite *HandlerSuite) TestSearchMovesHandler() { suite.NoError(payload.Validate(strfmt.Default)) // Get destination postal code and GBLOC based on business logic - moveDestinationPostalCode, err = moveWithShipmentPPM.GetDestinationPostalCode(suite.DB()) + moveDestinationAddress, err = moveWithShipmentPPM.GetDestinationAddress(suite.DB()) suite.NoError(err) moveDestinationGBLOC, err = moveWithShipmentPPM.GetDestinationGBLOC(suite.DB()) suite.NoError(err) - suite.Equal(moveDestinationPostalCode, payload.SearchMoves[0].DestinationPostalCode) + suite.Equal(moveDestinationAddress.PostalCode, payload.SearchMoves[0].DestinationPostalCode) suite.Equal(ghcmessages.GBLOC(moveDestinationGBLOC), payload.SearchMoves[0].DestinationGBLOC) }) } diff --git a/pkg/handlers/ghcapi/orders.go b/pkg/handlers/ghcapi/orders.go index f6b559513a2..51fec571935 100644 --- a/pkg/handlers/ghcapi/orders.go +++ b/pkg/handlers/ghcapi/orders.go @@ -219,21 +219,46 @@ func (h CreateOrderHandler) Handle(params orderop.CreateOrderParams) middleware. return orderop.NewCreateOrderUnprocessableEntity(), err } - destinationGBLOC, err := models.FetchGBLOCForPostalCode(appCtx.DB(), newDutyLocation.Address.PostalCode) - if err != nil { - err = apperror.NewBadDataError("New duty location GBLOC cannot be verified") - appCtx.Logger().Error(err.Error()) - return orderop.NewCreateOrderUnprocessableEntity(), err + var newDutyLocationGBLOC *string + if *newDutyLocation.Address.IsOconus { + newDutyLocationGBLOCOconus, err := models.FetchAddressGbloc(appCtx.DB(), newDutyLocation.Address, serviceMember) + if err != nil { + return nil, apperror.NewNotFoundError(newDutyLocation.ID, "while looking for New Duty Location Oconus GBLOC") + } + newDutyLocationGBLOC = newDutyLocationGBLOCOconus + } else { + newDutyLocationGBLOCConus, err := models.FetchGBLOCForPostalCode(appCtx.DB(), newDutyLocation.Address.PostalCode) + if err != nil { + switch err { + case sql.ErrNoRows: + return nil, apperror.NewNotFoundError(newDutyLocation.ID, "while looking for New Duty Location PostalCodeToGBLOC") + default: + err = apperror.NewBadDataError("New duty location GBLOC cannot be verified") + appCtx.Logger().Error(err.Error()) + return orderop.NewCreateOrderUnprocessableEntity(), err + } + } + newDutyLocationGBLOC = &newDutyLocationGBLOCConus.GBLOC } - originDutyLocationGBLOC, err := models.FetchGBLOCForPostalCode(appCtx.DB(), originDutyLocation.Address.PostalCode) - if err != nil { - switch err { - case sql.ErrNoRows: - return nil, apperror.NewNotFoundError(originDutyLocation.ID, "while looking for Duty Location PostalCodeToGBLOC") - default: - return nil, apperror.NewQueryError("PostalCodeToGBLOC", err, "") + var originDutyLocationGBLOC *string + if *originDutyLocation.Address.IsOconus { + originDutyLocationGBLOCOconus, err := models.FetchAddressGbloc(appCtx.DB(), originDutyLocation.Address, serviceMember) + if err != nil { + return nil, apperror.NewNotFoundError(originDutyLocation.ID, "while looking for Origin Duty Location Oconus GBLOC") + } + originDutyLocationGBLOC = originDutyLocationGBLOCOconus + } else { + originDutyLocationGBLOCConus, err := models.FetchGBLOCForPostalCode(appCtx.DB(), originDutyLocation.Address.PostalCode) + if err != nil { + switch err { + case sql.ErrNoRows: + return nil, apperror.NewNotFoundError(originDutyLocation.ID, "while looking for Origin Duty Location PostalCodeToGBLOC") + default: + return nil, apperror.NewQueryError("PostalCodeToGBLOC", err, "") + } } + originDutyLocationGBLOC = &originDutyLocationGBLOCConus.GBLOC } grade := (internalmessages.OrderPayGrade)(*payload.Grade) @@ -317,9 +342,9 @@ func (h CreateOrderHandler) Handle(params orderop.CreateOrderParams) middleware. &originDutyLocation, &grade, &entitlement, - &originDutyLocationGBLOC.GBLOC, + originDutyLocationGBLOC, packingAndShippingInstructions, - &destinationGBLOC.GBLOC, + newDutyLocationGBLOC, ) if err != nil || verrs.HasAny() { return handlers.ResponseForVErrors(appCtx.Logger(), verrs, err), err diff --git a/pkg/handlers/ghcapi/orders_test.go b/pkg/handlers/ghcapi/orders_test.go index d12d32534b5..68b984f2cef 100644 --- a/pkg/handlers/ghcapi/orders_test.go +++ b/pkg/handlers/ghcapi/orders_test.go @@ -32,6 +32,7 @@ import ( "github.com/transcom/mymove/pkg/services/query" storageTest "github.com/transcom/mymove/pkg/storage/test" "github.com/transcom/mymove/pkg/swagger/nullable" + "github.com/transcom/mymove/pkg/testdatagen" "github.com/transcom/mymove/pkg/trace" "github.com/transcom/mymove/pkg/uploader" ) @@ -110,20 +111,70 @@ func (suite *HandlerSuite) TestCreateOrder() { func (suite *HandlerSuite) TestCreateOrderWithOCONUSValues() { waf := entitlements.NewWeightAllotmentFetcher() - sm := factory.BuildExtendedServiceMember(suite.AppContextForTest().DB(), nil, nil) + customAffiliation := models.AffiliationARMY + sm := factory.BuildExtendedServiceMember(suite.DB(), []factory.Customization{ + { + Model: models.ServiceMember{ + Affiliation: &customAffiliation, + }, + }, + }, nil) officeUser := factory.BuildOfficeUserWithRoles(suite.AppContextForTest().DB(), nil, []roles.RoleType{roles.RoleTypeTOO}) - originDutyLocation := factory.BuildDutyLocation(suite.AppContextForTest().DB(), []factory.Customization{ + usprc, err := models.FindByZipCode(suite.AppContextForTest().DB(), "99801") + suite.NotNil(usprc) + suite.FatalNoError(err) + + address := factory.BuildAddress(suite.DB(), []factory.Customization{ + { + Model: models.Address{ + IsOconus: models.BoolPointer(true), + UsPostRegionCityID: &usprc.ID, + }, + }, + }, nil) + + originDutyLocation := factory.BuildDutyLocation(suite.DB(), []factory.Customization{ { Model: models.DutyLocation{ - Name: "Not Yuma AFB", + Name: factory.MakeRandomString(8), + AddressID: address.ID, }, }, }, nil) + dutyLocation := factory.FetchOrBuildCurrentDutyLocation(suite.AppContextForTest().DB()) - factory.FetchOrBuildPostalCodeToGBLOC(suite.AppContextForTest().DB(), dutyLocation.Address.PostalCode, "KKFA") - factory.FetchOrBuildDefaultContractor(suite.AppContextForTest().DB(), nil, nil) + contract := testdatagen.FetchOrMakeReContract(suite.DB(), testdatagen.Assertions{}) + + rateAreaCode := uuid.Must(uuid.NewV4()).String()[0:5] + rateArea := testdatagen.FetchOrMakeReRateArea(suite.DB(), testdatagen.Assertions{ + ReRateArea: models.ReRateArea{ + ContractID: contract.ID, + IsOconus: true, + Name: fmt.Sprintf("Alaska-%s", rateAreaCode), + Contract: contract, + }, + }) + suite.NotNil(rateArea) + + us_country, err := models.FetchCountryByCode(suite.DB(), "US") + suite.NotNil(us_country) + suite.Nil(err) + + oconusRateArea, err := models.FetchOconusRateAreaByCityId(suite.DB(), usprc.ID.String()) + suite.NotNil(oconusRateArea) + suite.Nil(err) + + jppsoRegion, err := models.FetchJppsoRegionByCode(suite.DB(), "MAPK") + suite.NotNil(jppsoRegion) + suite.Nil(err) + + gblocAors, err := models.FetchGblocAorsByJppsoCodeRateAreaDept(suite.DB(), jppsoRegion.ID, oconusRateArea.ID, models.DepartmentIndicatorARMY.String()) + suite.NotNil(gblocAors) + suite.Nil(err) + + factory.FetchOrBuildDefaultContractor(suite.AppContextForTest().DB(), nil, nil) req := httptest.NewRequest("POST", "/orders", nil) req = suite.AuthenticateOfficeRequest(req, officeUser) @@ -175,6 +226,7 @@ func (suite *HandlerSuite) TestCreateOrderWithOCONUSValues() { suite.Assertions.Equal(sm.ID.String(), okResponse.Payload.CustomerID.String()) suite.Assertions.Equal(ordersType, okResponse.Payload.OrderType) suite.Assertions.Equal(handlers.FmtString("123456"), okResponse.Payload.OrderNumber) + suite.Assertions.Equal(ghcmessages.GBLOC("MAPK"), okResponse.Payload.OriginDutyLocationGBLOC) suite.Assertions.Equal(handlers.FmtString("E19A"), okResponse.Payload.Tac) suite.Assertions.Equal(handlers.FmtString("SacNumber"), okResponse.Payload.Sac) suite.Assertions.Equal(&deptIndicator, okResponse.Payload.DepartmentIndicator) diff --git a/pkg/handlers/ghcapi/queues.go b/pkg/handlers/ghcapi/queues.go index 7763d9634de..f4b124cbb1c 100644 --- a/pkg/handlers/ghcapi/queues.go +++ b/pkg/handlers/ghcapi/queues.go @@ -178,6 +178,126 @@ func (h GetMovesQueueHandler) Handle(params queues.GetMovesQueueParams) middlewa }) } +// GetDestinationRequestsQueueHandler returns the moves for the TOO queue user via GET /queues/destination-requests +type GetDestinationRequestsQueueHandler struct { + handlers.HandlerConfig + services.OrderFetcher + services.MoveUnlocker + services.OfficeUserFetcherPop +} + +// Handle returns the paginated list of moves with destination requests for a TOO user +func (h GetDestinationRequestsQueueHandler) Handle(params queues.GetDestinationRequestsQueueParams) middleware.Responder { + return h.AuditableAppContextFromRequestWithErrors(params.HTTPRequest, + func(appCtx appcontext.AppContext) (middleware.Responder, error) { + if !appCtx.Session().IsOfficeUser() || + (!appCtx.Session().Roles.HasRole(roles.RoleTypeTOO)) { + forbiddenErr := apperror.NewForbiddenError( + "user is not authenticated with TOO role", + ) + appCtx.Logger().Error(forbiddenErr.Error()) + return queues.NewGetDestinationRequestsQueueForbidden(), forbiddenErr + } + + ListOrderParams := services.ListOrderParams{ + Branch: params.Branch, + Locator: params.Locator, + Edipi: params.Edipi, + Emplid: params.Emplid, + CustomerName: params.CustomerName, + DestinationDutyLocation: params.DestinationDutyLocation, + OriginDutyLocation: params.OriginDutyLocation, + AppearedInTOOAt: handlers.FmtDateTimePtrToPopPtr(params.AppearedInTooAt), + RequestedMoveDate: params.RequestedMoveDate, + Status: params.Status, + Page: params.Page, + PerPage: params.PerPage, + Sort: params.Sort, + Order: params.Order, + TOOAssignedUser: params.AssignedTo, + CounselingOffice: params.CounselingOffice, + } + + // we only care about moves in APPROVALS REQUESTED status + if params.Status == nil { + ListOrderParams.Status = []string{string(models.MoveStatusAPPROVALSREQUESTED)} + } + + // default pagination values + if params.Page == nil { + ListOrderParams.Page = models.Int64Pointer(1) + } + if params.PerPage == nil { + ListOrderParams.PerPage = models.Int64Pointer(20) + } + + moves, count, err := h.OrderFetcher.ListDestinationRequestsOrders( + appCtx, + appCtx.Session().OfficeUserID, + roles.RoleTypeTOO, + &ListOrderParams, + ) + if err != nil { + appCtx.Logger(). + Error("error fetching destinaton queue for office user", zap.Error(err)) + return queues.NewGetDestinationRequestsQueueInternalServerError(), err + } + + var officeUser models.OfficeUser + if appCtx.Session().OfficeUserID != uuid.Nil { + officeUser, err = h.OfficeUserFetcherPop.FetchOfficeUserByID(appCtx, appCtx.Session().OfficeUserID) + if err != nil { + appCtx.Logger().Error("Error retrieving office user", zap.Error(err)) + return queues.NewGetDestinationRequestsQueueInternalServerError(), err + } + } + privileges, err := models.FetchPrivilegesForUser(appCtx.DB(), appCtx.Session().UserID) + if err != nil { + appCtx.Logger().Error("Error retreiving user privileges", zap.Error(err)) + } + officeUser.User.Privileges = privileges + officeUser.User.Roles = appCtx.Session().Roles + + if err != nil { + appCtx.Logger(). + Error("error fetching office users", zap.Error(err)) + return queues.NewGetDestinationRequestsQueueInternalServerError(), err + } + + // if the TOO is accessing the queue, we need to unlock move/moves they have locked + if appCtx.Session().IsOfficeUser() { + officeUserID := appCtx.Session().OfficeUserID + for i, move := range moves { + lockedOfficeUserID := move.LockedByOfficeUserID + if lockedOfficeUserID != nil && *lockedOfficeUserID == officeUserID { + copyOfMove := move + unlockedMove, err := h.UnlockMove(appCtx, ©OfMove, officeUserID) + if err != nil { + return queues.NewGetDestinationRequestsQueueInternalServerError(), err + } + moves[i] = *unlockedMove + } + } + err := h.CheckForLockedMovesAndUnlock(appCtx, officeUserID) + if err != nil { + appCtx.Logger().Error(fmt.Sprintf("failed to unlock moves for office user ID: %s", officeUserID), zap.Error(err)) + } + } + + officeUsers := models.OfficeUsers{officeUser} + queueMoves := payloads.QueueMoves(moves, officeUsers, nil, officeUser, nil) + + result := &ghcmessages.QueueMovesResult{ + Page: *ListOrderParams.Page, + PerPage: *ListOrderParams.PerPage, + TotalCount: int64(count), + QueueMoves: *queueMoves, + } + + return queues.NewGetDestinationRequestsQueueOK().WithPayload(result), nil + }) +} + // ListMovesHandler lists moves with the option to filter since a particular date. Optimized ver. type ListPrimeMovesHandler struct { handlers.HandlerConfig diff --git a/pkg/handlers/ghcapi/queues_test.go b/pkg/handlers/ghcapi/queues_test.go index 4711af0de0a..6de9b13dd91 100644 --- a/pkg/handlers/ghcapi/queues_test.go +++ b/pkg/handlers/ghcapi/queues_test.go @@ -1893,3 +1893,144 @@ func (suite *HandlerSuite) TestGetBulkAssignmentDataHandler() { suite.Len(payload.BulkAssignmentMoveIDs, 1) }) } + +func (suite *HandlerSuite) TestGetDestinationRequestsQueuesHandler() { + waf := entitlements.NewWeightAllotmentFetcher() + // default GBLOC is KKFA + officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), factory.GetTraitActiveOfficeUser(), []roles.RoleType{roles.RoleTypeTOO}) + officeUser.User.Roles = append(officeUser.User.Roles, roles.Role{ + RoleType: roles.RoleTypeTOO, + }) + + postalCode := "90210" + postalCode2 := "73064" + factory.FetchOrBuildPostalCodeToGBLOC(suite.DB(), "90210", "KKFA") + factory.FetchOrBuildPostalCodeToGBLOC(suite.DB(), "73064", "JEAT") + + // setting up two moves, one we will see and the other we won't + move := factory.BuildAvailableToPrimeMove(suite.DB(), []factory.Customization{ + { + Model: models.Move{ + Status: models.MoveStatusAPPROVALSREQUESTED, + Show: models.BoolPointer(true), + }, + }}, nil) + + destinationAddress := factory.BuildAddress(suite.DB(), []factory.Customization{ + { + Model: models.Address{PostalCode: postalCode}, + }, + }, nil) + shipment := factory.BuildMTOShipment(suite.DB(), []factory.Customization{ + { + Model: models.MTOShipment{ + Status: models.MTOShipmentStatusApproved, + }, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: destinationAddress, + LinkOnly: true, + }, + }, nil) + + // destination service item in SUBMITTED status + factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeDDFSIT, + }, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusSubmitted, + }, + }, + }, nil) + + move2 := factory.BuildAvailableToPrimeMove(suite.DB(), []factory.Customization{ + { + Model: models.Move{ + Status: models.MoveStatusAPPROVALSREQUESTED, + Show: models.BoolPointer(true), + }, + }}, nil) + + destinationAddress2 := factory.BuildAddress(suite.DB(), []factory.Customization{ + { + Model: models.Address{PostalCode: postalCode2}, + }, + }, nil) + shipment2 := factory.BuildMTOShipment(suite.DB(), []factory.Customization{ + { + Model: models.MTOShipment{ + Status: models.MTOShipmentStatusApproved, + }, + }, + { + Model: move2, + LinkOnly: true, + }, + { + Model: destinationAddress2, + LinkOnly: true, + }, + }, nil) + + // destination shuttle + factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeDDSHUT, + }, + }, + { + Model: move2, + LinkOnly: true, + }, + { + Model: shipment2, + LinkOnly: true, + }, + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusSubmitted, + }, + }, + }, nil) + + request := httptest.NewRequest("GET", "/queues/destination-requests", nil) + request = suite.AuthenticateOfficeRequest(request, officeUser) + params := queues.GetDestinationRequestsQueueParams{ + HTTPRequest: request, + } + handlerConfig := suite.HandlerConfig() + mockUnlocker := movelocker.NewMoveUnlocker() + handler := GetDestinationRequestsQueueHandler{ + handlerConfig, + order.NewOrderFetcher(waf), + mockUnlocker, + officeusercreator.NewOfficeUserFetcherPop(), + } + + response := handler.Handle(params) + suite.IsNotErrResponse(response) + suite.IsType(&queues.GetDestinationRequestsQueueOK{}, response) + payload := response.(*queues.GetDestinationRequestsQueueOK).Payload + + // should only have one move + result := payload.QueueMoves[0] + suite.Len(payload.QueueMoves, 1) + suite.Equal(move.ID.String(), result.ID.String()) +} diff --git a/pkg/handlers/internalapi/orders.go b/pkg/handlers/internalapi/orders.go index 6e663bff4ea..84c8dfe126f 100644 --- a/pkg/handlers/internalapi/orders.go +++ b/pkg/handlers/internalapi/orders.go @@ -168,9 +168,26 @@ func (h CreateOrdersHandler) Handle(params ordersop.CreateOrdersParams) middlewa return handlers.ResponseForError(appCtx.Logger(), err), err } - newDutyLocationGBLOC, err := models.FetchGBLOCForPostalCode(appCtx.DB(), newDutyLocation.Address.PostalCode) - if err != nil { - return handlers.ResponseForError(appCtx.Logger(), err), err + var newDutyLocationGBLOC *string + if *newDutyLocation.Address.IsOconus { + newDutyLocationGBLOCOconus, err := models.FetchAddressGbloc(appCtx.DB(), newDutyLocation.Address, serviceMember) + if err != nil { + return nil, apperror.NewNotFoundError(newDutyLocation.ID, "while looking for New Duty Location Oconus GBLOC") + } + newDutyLocationGBLOC = newDutyLocationGBLOCOconus + } else { + newDutyLocationGBLOCConus, err := models.FetchGBLOCForPostalCode(appCtx.DB(), newDutyLocation.Address.PostalCode) + if err != nil { + switch err { + case sql.ErrNoRows: + return nil, apperror.NewNotFoundError(newDutyLocation.ID, "while looking for New Duty Location PostalCodeToGBLOC") + default: + err = apperror.NewBadDataError("New duty location GBLOC cannot be verified") + appCtx.Logger().Error(err.Error()) + return handlers.ResponseForError(appCtx.Logger(), err), err + } + } + newDutyLocationGBLOC = &newDutyLocationGBLOCConus.GBLOC } var dependentsTwelveAndOver *int @@ -184,14 +201,24 @@ func (h CreateOrdersHandler) Handle(params ordersop.CreateOrdersParams) middlewa dependentsUnderTwelve = models.IntPointer(int(*payload.DependentsUnderTwelve)) } - originDutyLocationGBLOC, err := models.FetchGBLOCForPostalCode(appCtx.DB(), originDutyLocation.Address.PostalCode) - if err != nil { - switch err { - case sql.ErrNoRows: - return nil, apperror.NewNotFoundError(originDutyLocation.ID, "while looking for Duty Location PostalCodeToGBLOC") - default: - return nil, apperror.NewQueryError("PostalCodeToGBLOC", err, "") + var originDutyLocationGBLOC *string + if *originDutyLocation.Address.IsOconus { + originDutyLocationGBLOCOconus, err := models.FetchAddressGbloc(appCtx.DB(), originDutyLocation.Address, serviceMember) + if err != nil { + return nil, apperror.NewNotFoundError(originDutyLocation.ID, "while looking for Origin Duty Location Oconus GBLOC") } + originDutyLocationGBLOC = originDutyLocationGBLOCOconus + } else { + originDutyLocationGBLOCConus, err := models.FetchGBLOCForPostalCode(appCtx.DB(), originDutyLocation.Address.PostalCode) + if err != nil { + switch err { + case sql.ErrNoRows: + return nil, apperror.NewNotFoundError(originDutyLocation.ID, "while looking for Origin Duty Location PostalCodeToGBLOC") + default: + return nil, apperror.NewQueryError("PostalCodeToGBLOC", err, "") + } + } + originDutyLocationGBLOC = &originDutyLocationGBLOCConus.GBLOC } grade := payload.Grade @@ -278,9 +305,9 @@ func (h CreateOrdersHandler) Handle(params ordersop.CreateOrdersParams) middlewa &originDutyLocation, grade, &entitlement, - &originDutyLocationGBLOC.GBLOC, + originDutyLocationGBLOC, packingAndShippingInstructions, - &newDutyLocationGBLOC.GBLOC, + newDutyLocationGBLOC, ) if err != nil || verrs.HasAny() { return handlers.ResponseForVErrors(appCtx.Logger(), verrs, err), err @@ -368,11 +395,26 @@ func (h UpdateOrdersHandler) Handle(params ordersop.UpdateOrdersParams) middlewa return handlers.ResponseForError(appCtx.Logger(), err), err } - newDutyLocationGBLOC, err := models.FetchGBLOCForPostalCode(appCtx.DB(), dutyLocation.Address.PostalCode) - if err != nil { - err = apperror.NewBadDataError("New duty location GBLOC cannot be verified") - appCtx.Logger().Error(err.Error()) - return handlers.ResponseForError(appCtx.Logger(), err), err + var newDutyLocationGBLOC *string + if *dutyLocation.Address.IsOconus { + newDutyLocationGBLOCOconus, err := models.FetchAddressGbloc(appCtx.DB(), dutyLocation.Address, order.ServiceMember) + if err != nil { + return nil, apperror.NewNotFoundError(dutyLocation.ID, "while looking for New Duty Location Oconus GBLOC") + } + newDutyLocationGBLOC = newDutyLocationGBLOCOconus + } else { + newDutyLocationGBLOCConus, err := models.FetchGBLOCForPostalCode(appCtx.DB(), dutyLocation.Address.PostalCode) + if err != nil { + switch err { + case sql.ErrNoRows: + return nil, apperror.NewNotFoundError(dutyLocation.ID, "while looking for New Duty Location PostalCodeToGBLOC") + default: + err = apperror.NewBadDataError("New duty location GBLOC cannot be verified") + appCtx.Logger().Error(err.Error()) + return handlers.ResponseForError(appCtx.Logger(), err), err + } + } + newDutyLocationGBLOC = &newDutyLocationGBLOCConus.GBLOC } if payload.OriginDutyLocationID != "" { @@ -387,11 +429,26 @@ func (h UpdateOrdersHandler) Handle(params ordersop.UpdateOrdersParams) middlewa order.OriginDutyLocation = &originDutyLocation order.OriginDutyLocationID = &originDutyLocationID - originGBLOC, originGBLOCerr := models.FetchGBLOCForPostalCode(appCtx.DB(), originDutyLocation.Address.PostalCode) - if originGBLOCerr != nil { - return handlers.ResponseForError(appCtx.Logger(), originGBLOCerr), originGBLOCerr + var originDutyLocationGBLOC *string + if *originDutyLocation.Address.IsOconus { + originDutyLocationGBLOCOconus, err := models.FetchAddressGbloc(appCtx.DB(), originDutyLocation.Address, order.ServiceMember) + if err != nil { + return handlers.ResponseForError(appCtx.Logger(), err), err + } + originDutyLocationGBLOC = originDutyLocationGBLOCOconus + } else { + originDutyLocationGBLOCConus, err := models.FetchGBLOCForPostalCode(appCtx.DB(), originDutyLocation.Address.PostalCode) + if err != nil { + switch err { + case sql.ErrNoRows: + return nil, apperror.NewNotFoundError(originDutyLocation.ID, "while looking for Origin Duty Location PostalCodeToGBLOC") + default: + return handlers.ResponseForError(appCtx.Logger(), err), err + } + } + originDutyLocationGBLOC = &originDutyLocationGBLOCConus.GBLOC } - order.OriginDutyLocationGBLOC = &originGBLOC.GBLOC + order.OriginDutyLocationGBLOC = originDutyLocationGBLOC if payload.MoveID != "" { @@ -433,7 +490,7 @@ func (h UpdateOrdersHandler) Handle(params ordersop.UpdateOrdersParams) middlewa order.SpouseHasProGear = *payload.SpouseHasProGear order.NewDutyLocationID = dutyLocation.ID order.NewDutyLocation = dutyLocation - order.DestinationGBLOC = &newDutyLocationGBLOC.GBLOC + order.DestinationGBLOC = newDutyLocationGBLOC order.TAC = payload.Tac order.SAC = payload.Sac diff --git a/pkg/handlers/internalapi/orders_test.go b/pkg/handlers/internalapi/orders_test.go index bf1b4a4303c..c26d5302ecf 100644 --- a/pkg/handlers/internalapi/orders_test.go +++ b/pkg/handlers/internalapi/orders_test.go @@ -22,126 +22,240 @@ import ( "github.com/transcom/mymove/pkg/services/move" orderservice "github.com/transcom/mymove/pkg/services/order" storageTest "github.com/transcom/mymove/pkg/storage/test" + "github.com/transcom/mymove/pkg/testdatagen" "github.com/transcom/mymove/pkg/uploader" ) func (suite *HandlerSuite) TestCreateOrder() { - sm := factory.BuildExtendedServiceMember(suite.DB(), nil, nil) - suite.Run("can create conus and oconus orders", func() { - testCases := []struct { - test string - isOconus bool - }{ - {test: "Can create OCONUS order", isOconus: true}, - {test: "Can create CONUS order", isOconus: false}, - } - for _, tc := range testCases { - address := factory.BuildAddress(suite.DB(), []factory.Customization{ - { - Model: models.Address{ - IsOconus: &tc.isOconus, - }, + customAffiliation := models.AffiliationARMY + sm := factory.BuildExtendedServiceMember(suite.DB(), []factory.Customization{ + { + Model: models.ServiceMember{ + Affiliation: &customAffiliation, + }, + }, + }, nil) + suite.Run("can create conus orders", func() { + address := factory.BuildAddress(suite.DB(), []factory.Customization{ + { + Model: models.Address{ + IsOconus: models.BoolPointer(false), }, - }, nil) + }, + }, nil) - originDutyLocation := factory.BuildDutyLocation(suite.DB(), []factory.Customization{ - { - Model: models.DutyLocation{ - Name: factory.MakeRandomString(8), - }, + originDutyLocation := factory.BuildDutyLocation(suite.DB(), []factory.Customization{ + { + Model: models.DutyLocation{ + Name: factory.MakeRandomString(8), + }, + }, + { + Model: address, + LinkOnly: true, + }, + }, nil) + + dutyLocation := factory.FetchOrBuildCurrentDutyLocation(suite.DB()) + factory.FetchOrBuildPostalCodeToGBLOC(suite.DB(), dutyLocation.Address.PostalCode, "KKFA") + factory.FetchOrBuildDefaultContractor(suite.DB(), nil, nil) + req := httptest.NewRequest("POST", "/orders", nil) + req = suite.AuthenticateRequest(req, sm) + + hasDependents := true + spouseHasProGear := true + issueDate := time.Date(2018, time.March, 10, 0, 0, 0, 0, time.UTC) + reportByDate := time.Date(2018, time.August, 1, 0, 0, 0, 0, time.UTC) + ordersType := internalmessages.OrdersTypePERMANENTCHANGEOFSTATION + deptIndicator := internalmessages.DeptIndicatorAIRANDSPACEFORCE + payload := &internalmessages.CreateUpdateOrders{ + HasDependents: handlers.FmtBool(hasDependents), + SpouseHasProGear: handlers.FmtBool(spouseHasProGear), + IssueDate: handlers.FmtDate(issueDate), + ReportByDate: handlers.FmtDate(reportByDate), + OrdersType: internalmessages.NewOrdersType(ordersType), + OriginDutyLocationID: *handlers.FmtUUIDPtr(&originDutyLocation.ID), + NewDutyLocationID: handlers.FmtUUID(dutyLocation.ID), + ServiceMemberID: handlers.FmtUUID(sm.ID), + OrdersNumber: handlers.FmtString("123456"), + Tac: handlers.FmtString("E19A"), + Sac: handlers.FmtString("SacNumber"), + DepartmentIndicator: internalmessages.NewDeptIndicator(deptIndicator), + Grade: models.ServiceMemberGradeE1.Pointer(), + } + + params := ordersop.CreateOrdersParams{ + HTTPRequest: req, + CreateOrders: payload, + } + + fakeS3 := storageTest.NewFakeS3Storage(true) + handlerConfig := suite.HandlerConfig() + handlerConfig.SetFileStorer(fakeS3) + createHandler := CreateOrdersHandler{handlerConfig} + + response := createHandler.Handle(params) + + suite.Assertions.IsType(&ordersop.CreateOrdersCreated{}, response) + okResponse := response.(*ordersop.CreateOrdersCreated) + orderID := okResponse.Payload.ID.String() + createdOrder, _ := models.FetchOrder(suite.DB(), uuid.FromStringOrNil(orderID)) + var createdEntitlement models.Entitlement + err := suite.DB().Find(&createdEntitlement, createdOrder.EntitlementID) + suite.NoError(err) + suite.NotEmpty(createdEntitlement) + suite.Assertions.Equal(sm.ID.String(), okResponse.Payload.ServiceMemberID.String()) + suite.Assertions.Len(okResponse.Payload.Moves, 1) + suite.Assertions.Equal(ordersType, *okResponse.Payload.OrdersType) + suite.Assertions.Equal(handlers.FmtString("123456"), okResponse.Payload.OrdersNumber) + suite.Assertions.Equal(handlers.FmtString("E19A"), okResponse.Payload.Tac) + suite.Assertions.Equal(handlers.FmtString("SacNumber"), okResponse.Payload.Sac) + suite.Assertions.Equal(&deptIndicator, okResponse.Payload.DepartmentIndicator) + suite.Assertions.Equal(*models.Int64Pointer(8000), *okResponse.Payload.AuthorizedWeight) + suite.NotNil(&createdOrder.Entitlement) + suite.NotEmpty(createdOrder.SupplyAndServicesCostEstimate) + suite.NotEmpty(createdOrder.PackingAndShippingInstructions) + suite.NotEmpty(createdOrder.MethodOfPayment) + suite.NotEmpty(createdOrder.NAICS) + suite.Nil(createdEntitlement.AccompaniedTour) + suite.Nil(createdEntitlement.DependentsTwelveAndOver) + suite.Nil(createdEntitlement.DependentsUnderTwelve) + }) + + suite.Run("can create oconus orders", func() { + usprc, err := models.FindByZipCode(suite.AppContextForTest().DB(), "99801") + suite.NotNil(usprc) + suite.FatalNoError(err) + + address := factory.BuildAddress(suite.DB(), []factory.Customization{ + { + Model: models.Address{ + IsOconus: models.BoolPointer(true), + UsPostRegionCityID: &usprc.ID, }, - { - Model: address, - LinkOnly: true, + }, + }, nil) + + originDutyLocation := factory.BuildDutyLocation(suite.DB(), []factory.Customization{ + { + Model: models.DutyLocation{ + Name: factory.MakeRandomString(8), + AddressID: address.ID, }, - }, nil) - - dutyLocation := factory.FetchOrBuildCurrentDutyLocation(suite.DB()) - factory.FetchOrBuildPostalCodeToGBLOC(suite.DB(), dutyLocation.Address.PostalCode, "KKFA") - factory.FetchOrBuildDefaultContractor(suite.DB(), nil, nil) - - req := httptest.NewRequest("POST", "/orders", nil) - req = suite.AuthenticateRequest(req, sm) - - hasDependents := true - spouseHasProGear := true - issueDate := time.Date(2018, time.March, 10, 0, 0, 0, 0, time.UTC) - reportByDate := time.Date(2018, time.August, 1, 0, 0, 0, 0, time.UTC) - ordersType := internalmessages.OrdersTypePERMANENTCHANGEOFSTATION - deptIndicator := internalmessages.DeptIndicatorAIRANDSPACEFORCE - payload := &internalmessages.CreateUpdateOrders{ - HasDependents: handlers.FmtBool(hasDependents), - SpouseHasProGear: handlers.FmtBool(spouseHasProGear), - IssueDate: handlers.FmtDate(issueDate), - ReportByDate: handlers.FmtDate(reportByDate), - OrdersType: internalmessages.NewOrdersType(ordersType), - OriginDutyLocationID: *handlers.FmtUUIDPtr(&originDutyLocation.ID), - NewDutyLocationID: handlers.FmtUUID(dutyLocation.ID), - ServiceMemberID: handlers.FmtUUID(sm.ID), - OrdersNumber: handlers.FmtString("123456"), - Tac: handlers.FmtString("E19A"), - Sac: handlers.FmtString("SacNumber"), - DepartmentIndicator: internalmessages.NewDeptIndicator(deptIndicator), - Grade: models.ServiceMemberGradeE1.Pointer(), - } + }, + }, nil) - if tc.isOconus { - payload.AccompaniedTour = models.BoolPointer(true) - payload.DependentsTwelveAndOver = models.Int64Pointer(5) - payload.DependentsUnderTwelve = models.Int64Pointer(5) - } + dutyLocation := factory.FetchOrBuildCurrentDutyLocation(suite.DB()) - params := ordersop.CreateOrdersParams{ - HTTPRequest: req, - CreateOrders: payload, - } + contract := testdatagen.FetchOrMakeReContract(suite.DB(), testdatagen.Assertions{}) - fakeS3 := storageTest.NewFakeS3Storage(true) - handlerConfig := suite.HandlerConfig() - handlerConfig.SetFileStorer(fakeS3) - createHandler := CreateOrdersHandler{handlerConfig} - - response := createHandler.Handle(params) - - suite.Assertions.IsType(&ordersop.CreateOrdersCreated{}, response) - okResponse := response.(*ordersop.CreateOrdersCreated) - orderID := okResponse.Payload.ID.String() - createdOrder, _ := models.FetchOrder(suite.DB(), uuid.FromStringOrNil(orderID)) - var createdEntitlement models.Entitlement - err := suite.DB().Find(&createdEntitlement, createdOrder.EntitlementID) - suite.NoError(err) - suite.NotEmpty(createdEntitlement) - suite.Assertions.Equal(sm.ID.String(), okResponse.Payload.ServiceMemberID.String()) - suite.Assertions.Len(okResponse.Payload.Moves, 1) - suite.Assertions.Equal(ordersType, *okResponse.Payload.OrdersType) - suite.Assertions.Equal(handlers.FmtString("123456"), okResponse.Payload.OrdersNumber) - suite.Assertions.Equal(handlers.FmtString("E19A"), okResponse.Payload.Tac) - suite.Assertions.Equal(handlers.FmtString("SacNumber"), okResponse.Payload.Sac) - suite.Assertions.Equal(&deptIndicator, okResponse.Payload.DepartmentIndicator) - suite.Assertions.Equal(*models.Int64Pointer(8000), *okResponse.Payload.AuthorizedWeight) - suite.NotNil(&createdOrder.Entitlement) - suite.NotEmpty(createdOrder.SupplyAndServicesCostEstimate) - suite.NotEmpty(createdOrder.PackingAndShippingInstructions) - suite.NotEmpty(createdOrder.MethodOfPayment) - suite.NotEmpty(createdOrder.NAICS) - if tc.isOconus { - suite.NotNil(createdEntitlement.AccompaniedTour) - suite.NotNil(createdEntitlement.DependentsTwelveAndOver) - suite.NotNil(createdEntitlement.DependentsUnderTwelve) - } else { - suite.Nil(createdEntitlement.AccompaniedTour) - suite.Nil(createdEntitlement.DependentsTwelveAndOver) - suite.Nil(createdEntitlement.DependentsUnderTwelve) - } + rateAreaCode := uuid.Must(uuid.NewV4()).String()[0:5] + rateArea := testdatagen.FetchOrMakeReRateArea(suite.DB(), testdatagen.Assertions{ + ReRateArea: models.ReRateArea{ + ContractID: contract.ID, + IsOconus: true, + Name: fmt.Sprintf("Alaska-%s", rateAreaCode), + Contract: contract, + }, + }) + suite.NotNil(rateArea) + suite.Nil(err) + + us_country, err := models.FetchCountryByCode(suite.DB(), "US") + suite.NotNil(us_country) + suite.Nil(err) + + oconusRateArea, err := models.FetchOconusRateAreaByCityId(suite.DB(), usprc.ID.String()) + suite.NotNil(oconusRateArea) + suite.Nil(err) + + jppsoRegion, err := models.FetchJppsoRegionByCode(suite.DB(), "MAPK") + suite.NotNil(jppsoRegion) + suite.Nil(err) + gblocAors, err := models.FetchGblocAorsByJppsoCodeRateAreaDept(suite.DB(), jppsoRegion.ID, oconusRateArea.ID, models.DepartmentIndicatorARMY.String()) + suite.NotNil(gblocAors) + suite.Nil(err) + + factory.FetchOrBuildDefaultContractor(suite.DB(), nil, nil) + req := httptest.NewRequest("POST", "/orders", nil) + req = suite.AuthenticateRequest(req, sm) + + hasDependents := true + spouseHasProGear := true + issueDate := time.Date(2018, time.March, 10, 0, 0, 0, 0, time.UTC) + reportByDate := time.Date(2018, time.August, 1, 0, 0, 0, 0, time.UTC) + ordersType := internalmessages.OrdersTypePERMANENTCHANGEOFSTATION + deptIndicator := internalmessages.DeptIndicatorAIRANDSPACEFORCE + payload := &internalmessages.CreateUpdateOrders{ + HasDependents: handlers.FmtBool(hasDependents), + SpouseHasProGear: handlers.FmtBool(spouseHasProGear), + IssueDate: handlers.FmtDate(issueDate), + ReportByDate: handlers.FmtDate(reportByDate), + OrdersType: internalmessages.NewOrdersType(ordersType), + OriginDutyLocationID: *handlers.FmtUUIDPtr(&originDutyLocation.ID), + NewDutyLocationID: handlers.FmtUUID(dutyLocation.ID), + ServiceMemberID: handlers.FmtUUID(sm.ID), + OrdersNumber: handlers.FmtString("123456"), + Tac: handlers.FmtString("E19A"), + Sac: handlers.FmtString("SacNumber"), + DepartmentIndicator: internalmessages.NewDeptIndicator(deptIndicator), + Grade: models.ServiceMemberGradeE1.Pointer(), + AccompaniedTour: models.BoolPointer(true), + DependentsTwelveAndOver: models.Int64Pointer(5), + DependentsUnderTwelve: models.Int64Pointer(5), } + + params := ordersop.CreateOrdersParams{ + HTTPRequest: req, + CreateOrders: payload, + } + + fakeS3 := storageTest.NewFakeS3Storage(true) + handlerConfig := suite.HandlerConfig() + handlerConfig.SetFileStorer(fakeS3) + createHandler := CreateOrdersHandler{handlerConfig} + response := createHandler.Handle(params) + + suite.Assertions.IsType(&ordersop.CreateOrdersCreated{}, response) + okResponse := response.(*ordersop.CreateOrdersCreated) + + orderID := okResponse.Payload.ID.String() + createdOrder, _ := models.FetchOrder(suite.DB(), uuid.FromStringOrNil(orderID)) + var createdEntitlement models.Entitlement + err = suite.DB().Find(&createdEntitlement, createdOrder.EntitlementID) + suite.NoError(err) + suite.NotEmpty(createdEntitlement) + suite.Assertions.Equal(sm.ID.String(), okResponse.Payload.ServiceMemberID.String()) + suite.Assertions.Len(okResponse.Payload.Moves, 1) + suite.Assertions.Equal(ordersType, *okResponse.Payload.OrdersType) + suite.Assertions.Equal(handlers.FmtString("123456"), okResponse.Payload.OrdersNumber) + suite.Assertions.Equal(handlers.FmtString("MAPK"), okResponse.Payload.OriginDutyLocationGbloc) + suite.Assertions.Equal(handlers.FmtString("E19A"), okResponse.Payload.Tac) + suite.Assertions.Equal(handlers.FmtString("SacNumber"), okResponse.Payload.Sac) + suite.Assertions.Equal(&deptIndicator, okResponse.Payload.DepartmentIndicator) + suite.Assertions.Equal(*models.Int64Pointer(8000), *okResponse.Payload.AuthorizedWeight) + suite.NotNil(&createdOrder.Entitlement) + suite.NotEmpty(createdOrder.SupplyAndServicesCostEstimate) + suite.NotEmpty(createdOrder.PackingAndShippingInstructions) + suite.NotEmpty(createdOrder.MethodOfPayment) + suite.NotEmpty(createdOrder.NAICS) + suite.NotNil(createdEntitlement.AccompaniedTour) + suite.NotNil(createdEntitlement.DependentsTwelveAndOver) + suite.NotNil(createdEntitlement.DependentsUnderTwelve) + }) suite.Run("properly handles entitlement validation", func() { + usprc, err := models.FindByZipCode(suite.AppContextForTest().DB(), "99506") + suite.NotNil(usprc) + suite.FatalNoError(err) + address := factory.BuildAddress(suite.DB(), []factory.Customization{ { Model: models.Address{ - IsOconus: models.BoolPointer(true), + IsOconus: models.BoolPointer(true), + UsPostRegionCityID: &usprc.ID, }, }, }, nil) @@ -149,17 +263,43 @@ func (suite *HandlerSuite) TestCreateOrder() { originDutyLocation := factory.BuildDutyLocation(suite.DB(), []factory.Customization{ { Model: models.DutyLocation{ - Name: factory.MakeRandomString(8), + Name: factory.MakeRandomString(8), + AddressID: address.ID, }, }, - { - Model: address, - LinkOnly: true, - }, }, nil) dutyLocation := factory.FetchOrBuildCurrentDutyLocation(suite.DB()) - factory.FetchOrBuildPostalCodeToGBLOC(suite.DB(), dutyLocation.Address.PostalCode, "KKFA") + + contract := testdatagen.FetchOrMakeReContract(suite.DB(), testdatagen.Assertions{}) + + rateAreaCode := uuid.Must(uuid.NewV4()).String()[0:5] + rateArea := testdatagen.FetchOrMakeReRateArea(suite.DB(), testdatagen.Assertions{ + ReRateArea: models.ReRateArea{ + ContractID: contract.ID, + IsOconus: true, + Name: fmt.Sprintf("Alaska-%s", rateAreaCode), + Contract: contract, + }, + }) + suite.NotNil(rateArea) + + us_country, err := models.FetchCountryByCode(suite.DB(), "US") + suite.NotNil(us_country) + suite.Nil(err) + + oconusRateArea, err := models.FetchOconusRateAreaByCityId(suite.DB(), usprc.ID.String()) + suite.NotNil(oconusRateArea) + suite.Nil(err) + + jppsoRegion, err := models.FetchJppsoRegionByCode(suite.DB(), "MBFL") + suite.NotNil(jppsoRegion) + suite.Nil(err) + + gblocAors, err := models.FetchGblocAorsByJppsoCodeRateAreaDept(suite.DB(), jppsoRegion.ID, oconusRateArea.ID, models.DepartmentIndicatorARMY.String()) + suite.NotNil(gblocAors) + suite.Nil(err) + factory.FetchOrBuildDefaultContractor(suite.DB(), nil, nil) req := httptest.NewRequest("POST", "/orders", nil) @@ -577,144 +717,272 @@ func (suite *HandlerSuite) TestUploadAmendedOrdersHandlerIntegration() { func (suite *HandlerSuite) TestUpdateOrdersHandler() { waf := entitlements.NewWeightAllotmentFetcher() - suite.Run("Can update CONUS and OCONUS orders", func() { - testCases := []struct { - isOconus bool - }{ - {isOconus: true}, - {isOconus: false}, - } - - for _, tc := range testCases { - address := factory.BuildAddress(suite.DB(), []factory.Customization{ - { - Model: models.Address{ - IsOconus: &tc.isOconus, - }, + suite.Run("Can update CONUS orders", func() { + address := factory.BuildAddress(suite.DB(), []factory.Customization{ + { + Model: models.Address{ + IsOconus: models.BoolPointer(false), }, - }, nil) + }, + }, nil) - // Set duty location to either CONUS or OCONUS - dutyLocation := factory.BuildDutyLocation(suite.DB(), []factory.Customization{ - { - Model: models.DutyLocation{ - ProvidesServicesCounseling: false, - }, + originDutyLocation := factory.BuildDutyLocation(suite.DB(), []factory.Customization{ + { + Model: models.DutyLocation{ + Name: factory.MakeRandomString(8), }, - { - Model: address, - LinkOnly: true, + }, + { + Model: address, + LinkOnly: true, + }, + }, nil) + order := factory.BuildOrder(suite.DB(), []factory.Customization{ + { + Model: originDutyLocation, + LinkOnly: true, + Type: &factory.DutyLocations.OriginDutyLocation, + }, + }, nil) + move := factory.BuildMove(suite.DB(), []factory.Customization{ + { + Model: order, + LinkOnly: true, + }}, nil) + + newDutyLocation := factory.BuildDutyLocation(suite.DB(), nil, nil) + + newOrdersType := internalmessages.OrdersTypePERMANENTCHANGEOFSTATION + newOrdersNumber := "123456" + issueDate := time.Date(2018, time.March, 10, 0, 0, 0, 0, time.UTC) + reportByDate := time.Date(2018, time.August, 1, 0, 0, 0, 0, time.UTC) + deptIndicator := internalmessages.DeptIndicatorAIRANDSPACEFORCE + + payload := &internalmessages.CreateUpdateOrders{ + OrdersNumber: handlers.FmtString(newOrdersNumber), + OrdersType: &newOrdersType, + NewDutyLocationID: handlers.FmtUUID(newDutyLocation.ID), + OriginDutyLocationID: *handlers.FmtUUID(*order.OriginDutyLocationID), + IssueDate: handlers.FmtDate(issueDate), + ReportByDate: handlers.FmtDate(reportByDate), + DepartmentIndicator: &deptIndicator, + HasDependents: handlers.FmtBool(false), + SpouseHasProGear: handlers.FmtBool(false), + Grade: models.ServiceMemberGradeE4.Pointer(), + MoveID: *handlers.FmtUUID(move.ID), + CounselingOfficeID: handlers.FmtUUID(*newDutyLocation.TransportationOfficeID), + ServiceMemberID: handlers.FmtUUID(order.ServiceMemberID), + } + + path := fmt.Sprintf("/orders/%v", order.ID.String()) + req := httptest.NewRequest("PUT", path, nil) + req = suite.AuthenticateRequest(req, order.ServiceMember) + + params := ordersop.UpdateOrdersParams{ + HTTPRequest: req, + OrdersID: *handlers.FmtUUID(order.ID), + UpdateOrders: payload, + } + + fakeS3 := storageTest.NewFakeS3Storage(true) + handlerConfig := suite.HandlerConfig() + handlerConfig.SetFileStorer(fakeS3) + + handler := UpdateOrdersHandler{handlerConfig} + + response := handler.Handle(params) + + suite.IsType(&ordersop.UpdateOrdersOK{}, response) + okResponse := response.(*ordersop.UpdateOrdersOK) + + suite.NoError(okResponse.Payload.Validate(strfmt.Default)) + suite.Equal(string(newOrdersType), string(*okResponse.Payload.OrdersType)) + suite.Equal(newOrdersNumber, *okResponse.Payload.OrdersNumber) + + updatedOrder, err := models.FetchOrder(suite.DB(), order.ID) + suite.NoError(err) + suite.Equal(payload.Grade, updatedOrder.Grade) + suite.Equal(*okResponse.Payload.AuthorizedWeight, int64(7000)) // E4 authorized weight is 7000, make sure we return that in the response + expectedUpdatedOrderWeightAllotment, err := waf.GetWeightAllotment(suite.AppContextForTest(), string(*updatedOrder.Grade), updatedOrder.OrdersType) + suite.NoError(err) + expectedUpdatedOrderAuthorizedWeight := expectedUpdatedOrderWeightAllotment.TotalWeightSelf + if *payload.HasDependents { + expectedUpdatedOrderAuthorizedWeight = expectedUpdatedOrderWeightAllotment.TotalWeightSelfPlusDependents + } + + expectedOriginalOrderWeightAllotment, err := waf.GetWeightAllotment(suite.AppContextForTest(), string(*order.Grade), updatedOrder.OrdersType) + suite.NoError(err) + expectedOriginalOrderAuthorizedWeight := expectedOriginalOrderWeightAllotment.TotalWeightSelf + if *payload.HasDependents { + expectedUpdatedOrderAuthorizedWeight = expectedOriginalOrderWeightAllotment.TotalWeightSelfPlusDependents + } + + suite.Equal(expectedUpdatedOrderAuthorizedWeight, 7000) // Ensure that when GetWeightAllotment is recalculated that it also returns 7000. This ensures that the database stored the correct information + suite.Equal(expectedOriginalOrderAuthorizedWeight, 5000) // The order was created as an E1. Ensure that the E1 authorized weight is 5000. + suite.Equal(string(newOrdersType), string(updatedOrder.OrdersType)) + // Check updated entitlement + var updatedEntitlement models.Entitlement + err = suite.DB().Find(&updatedEntitlement, updatedOrder.EntitlementID) + suite.NoError(err) + suite.NotEmpty(updatedEntitlement) + + suite.Nil(updatedEntitlement.AccompaniedTour) + suite.Nil(updatedEntitlement.DependentsTwelveAndOver) + suite.Nil(updatedEntitlement.DependentsUnderTwelve) + }) + + suite.Run("Can update OCONUS orders", func() { + usprc, err := models.FindByZipCode(suite.AppContextForTest().DB(), "99801") + suite.NotNil(usprc) + suite.FatalNoError(err) + + address := factory.BuildAddress(suite.DB(), []factory.Customization{ + { + Model: models.Address{ + IsOconus: models.BoolPointer(true), + UsPostRegionCityID: &usprc.ID, }, - }, nil) - order := factory.BuildOrder(suite.DB(), []factory.Customization{ - { - Model: dutyLocation, - LinkOnly: true, - Type: &factory.DutyLocations.OriginDutyLocation, + }, + }, nil) + + originDutyLocation := factory.BuildDutyLocation(suite.DB(), []factory.Customization{ + { + Model: models.DutyLocation{ + Name: factory.MakeRandomString(8), + AddressID: address.ID, }, - }, nil) - move := factory.BuildMove(suite.DB(), []factory.Customization{ - { - Model: order, - LinkOnly: true, - }}, nil) - - newDutyLocation := factory.BuildDutyLocation(suite.DB(), nil, nil) - newTransportationOffice := factory.BuildTransportationOffice(suite.DB(), nil, nil) - newDutyLocation.TransportationOffice = newTransportationOffice - - newOrdersType := internalmessages.OrdersTypePERMANENTCHANGEOFSTATION - newOrdersNumber := "123456" - issueDate := time.Date(2018, time.March, 10, 0, 0, 0, 0, time.UTC) - reportByDate := time.Date(2018, time.August, 1, 0, 0, 0, 0, time.UTC) - deptIndicator := internalmessages.DeptIndicatorAIRANDSPACEFORCE - - payload := &internalmessages.CreateUpdateOrders{ - OrdersNumber: handlers.FmtString(newOrdersNumber), - OrdersType: &newOrdersType, - NewDutyLocationID: handlers.FmtUUID(newDutyLocation.ID), - OriginDutyLocationID: *handlers.FmtUUID(*order.OriginDutyLocationID), - IssueDate: handlers.FmtDate(issueDate), - ReportByDate: handlers.FmtDate(reportByDate), - DepartmentIndicator: &deptIndicator, - HasDependents: handlers.FmtBool(false), - SpouseHasProGear: handlers.FmtBool(false), - Grade: models.ServiceMemberGradeE4.Pointer(), - MoveID: *handlers.FmtUUID(move.ID), - CounselingOfficeID: handlers.FmtUUID(*newDutyLocation.TransportationOfficeID), - ServiceMemberID: handlers.FmtUUID(order.ServiceMemberID), - } - // The default move factory does not include OCONUS fields, set these - // new fields conditionally for the update - if tc.isOconus { - payload.AccompaniedTour = models.BoolPointer(true) - payload.DependentsTwelveAndOver = models.Int64Pointer(5) - payload.DependentsUnderTwelve = models.Int64Pointer(5) - } + }, + }, nil) - path := fmt.Sprintf("/orders/%v", order.ID.String()) - req := httptest.NewRequest("PUT", path, nil) - req = suite.AuthenticateRequest(req, order.ServiceMember) + order := factory.BuildOrder(suite.DB(), []factory.Customization{ + { + Model: originDutyLocation, + LinkOnly: true, + Type: &factory.DutyLocations.OriginDutyLocation, + }, + }, nil) - params := ordersop.UpdateOrdersParams{ - HTTPRequest: req, - OrdersID: *handlers.FmtUUID(order.ID), - UpdateOrders: payload, - } + move := factory.BuildMove(suite.DB(), []factory.Customization{ + { + Model: order, + LinkOnly: true, + }}, nil) - fakeS3 := storageTest.NewFakeS3Storage(true) - handlerConfig := suite.HandlerConfig() - handlerConfig.SetFileStorer(fakeS3) + newDutyLocation := factory.BuildDutyLocation(suite.DB(), nil, nil) - handler := UpdateOrdersHandler{handlerConfig} + contract := testdatagen.FetchOrMakeReContract(suite.DB(), testdatagen.Assertions{}) - response := handler.Handle(params) + rateAreaCode := uuid.Must(uuid.NewV4()).String()[0:5] + rateArea := testdatagen.FetchOrMakeReRateArea(suite.DB(), testdatagen.Assertions{ + ReRateArea: models.ReRateArea{ + ContractID: contract.ID, + IsOconus: true, + Name: fmt.Sprintf("Alaska-%s", rateAreaCode), + Contract: contract, + }, + }) + suite.NotNil(rateArea) + suite.Nil(err) - suite.IsType(&ordersop.UpdateOrdersOK{}, response) - okResponse := response.(*ordersop.UpdateOrdersOK) + us_country, err := models.FetchCountryByCode(suite.DB(), "US") + suite.NotNil(us_country) + suite.Nil(err) - suite.NoError(okResponse.Payload.Validate(strfmt.Default)) - suite.Equal(string(newOrdersType), string(*okResponse.Payload.OrdersType)) - suite.Equal(newOrdersNumber, *okResponse.Payload.OrdersNumber) + oconusRateArea, err := models.FetchOconusRateAreaByCityId(suite.DB(), usprc.ID.String()) + suite.NotNil(oconusRateArea) + suite.Nil(err) - updatedOrder, err := models.FetchOrder(suite.DB(), order.ID) - suite.NoError(err) - suite.Equal(payload.Grade, updatedOrder.Grade) - suite.Equal(*okResponse.Payload.AuthorizedWeight, int64(7000)) // E4 authorized weight is 7000, make sure we return that in the response - expectedUpdatedOrderWeightAllotment, err := waf.GetWeightAllotment(suite.AppContextForTest(), string(*updatedOrder.Grade), updatedOrder.OrdersType) - suite.NoError(err) - expectedUpdatedOrderAuthorizedWeight := expectedUpdatedOrderWeightAllotment.TotalWeightSelf - if *payload.HasDependents { - expectedUpdatedOrderAuthorizedWeight = expectedUpdatedOrderWeightAllotment.TotalWeightSelfPlusDependents - } + jppsoRegion, err := models.FetchJppsoRegionByCode(suite.DB(), "MAPK") + suite.NotNil(jppsoRegion) + suite.Nil(err) - expectedOriginalOrderWeightAllotment, err := waf.GetWeightAllotment(suite.AppContextForTest(), string(*order.Grade), updatedOrder.OrdersType) - suite.NoError(err) - expectedOriginalOrderAuthorizedWeight := expectedOriginalOrderWeightAllotment.TotalWeightSelf - if *payload.HasDependents { - expectedUpdatedOrderAuthorizedWeight = expectedOriginalOrderWeightAllotment.TotalWeightSelfPlusDependents - } + gblocAors, err := models.FetchGblocAorsByJppsoCodeRateAreaDept(suite.DB(), jppsoRegion.ID, oconusRateArea.ID, models.DepartmentIndicatorARMY.String()) + suite.NotNil(gblocAors) + suite.Nil(err) - suite.Equal(expectedUpdatedOrderAuthorizedWeight, 7000) // Ensure that when GetWeightAllotment is recalculated that it also returns 7000. This ensures that the database stored the correct information - suite.Equal(expectedOriginalOrderAuthorizedWeight, 5000) // The order was created as an E1. Ensure that the E1 authorized weight is 5000. - suite.Equal(string(newOrdersType), string(updatedOrder.OrdersType)) - // Check updated entitlement - var updatedEntitlement models.Entitlement - err = suite.DB().Find(&updatedEntitlement, updatedOrder.EntitlementID) - suite.NoError(err) - suite.NotEmpty(updatedEntitlement) - - if tc.isOconus { - suite.NotNil(updatedEntitlement.AccompaniedTour) - suite.NotNil(updatedEntitlement.DependentsTwelveAndOver) - suite.NotNil(updatedEntitlement.DependentsUnderTwelve) - } else { - suite.Nil(updatedEntitlement.AccompaniedTour) - suite.Nil(updatedEntitlement.DependentsTwelveAndOver) - suite.Nil(updatedEntitlement.DependentsUnderTwelve) - } + newOrdersType := internalmessages.OrdersTypePERMANENTCHANGEOFSTATION + newOrdersNumber := "123456" + issueDate := time.Date(2018, time.March, 10, 0, 0, 0, 0, time.UTC) + reportByDate := time.Date(2018, time.August, 1, 0, 0, 0, 0, time.UTC) + deptIndicator := internalmessages.DeptIndicatorAIRANDSPACEFORCE + + payload := &internalmessages.CreateUpdateOrders{ + OrdersNumber: handlers.FmtString(newOrdersNumber), + OrdersType: &newOrdersType, + NewDutyLocationID: handlers.FmtUUID(newDutyLocation.ID), + OriginDutyLocationID: *handlers.FmtUUID(*order.OriginDutyLocationID), + IssueDate: handlers.FmtDate(issueDate), + ReportByDate: handlers.FmtDate(reportByDate), + DepartmentIndicator: &deptIndicator, + HasDependents: handlers.FmtBool(false), + SpouseHasProGear: handlers.FmtBool(false), + Grade: models.ServiceMemberGradeE4.Pointer(), + MoveID: *handlers.FmtUUID(move.ID), + CounselingOfficeID: handlers.FmtUUID(*newDutyLocation.TransportationOfficeID), + ServiceMemberID: handlers.FmtUUID(order.ServiceMemberID), + } + + payload.AccompaniedTour = models.BoolPointer(true) + payload.DependentsTwelveAndOver = models.Int64Pointer(5) + payload.DependentsUnderTwelve = models.Int64Pointer(5) + + path := fmt.Sprintf("/orders/%v", order.ID.String()) + req := httptest.NewRequest("PUT", path, nil) + req = suite.AuthenticateRequest(req, order.ServiceMember) + + params := ordersop.UpdateOrdersParams{ + HTTPRequest: req, + OrdersID: *handlers.FmtUUID(order.ID), + UpdateOrders: payload, } + + fakeS3 := storageTest.NewFakeS3Storage(true) + handlerConfig := suite.HandlerConfig() + handlerConfig.SetFileStorer(fakeS3) + + handler := UpdateOrdersHandler{handlerConfig} + + response := handler.Handle(params) + + suite.IsType(&ordersop.UpdateOrdersOK{}, response) + okResponse := response.(*ordersop.UpdateOrdersOK) + + suite.NoError(okResponse.Payload.Validate(strfmt.Default)) + suite.Equal(string(newOrdersType), string(*okResponse.Payload.OrdersType)) + suite.Equal(newOrdersNumber, *okResponse.Payload.OrdersNumber) + + updatedOrder, err := models.FetchOrder(suite.DB(), order.ID) + suite.NoError(err) + suite.Equal(payload.Grade, updatedOrder.Grade) + suite.Equal(*okResponse.Payload.AuthorizedWeight, int64(7000)) // E4 authorized weight is 7000, make sure we return that in the response + expectedUpdatedOrderWeightAllotment, err := waf.GetWeightAllotment(suite.AppContextForTest(), string(*updatedOrder.Grade), updatedOrder.OrdersType) + suite.NoError(err) + expectedUpdatedOrderAuthorizedWeight := expectedUpdatedOrderWeightAllotment.TotalWeightSelf + if *payload.HasDependents { + expectedUpdatedOrderAuthorizedWeight = expectedUpdatedOrderWeightAllotment.TotalWeightSelfPlusDependents + } + + expectedOriginalOrderWeightAllotment, err := waf.GetWeightAllotment(suite.AppContextForTest(), string(*order.Grade), updatedOrder.OrdersType) + suite.NoError(err) + expectedOriginalOrderAuthorizedWeight := expectedOriginalOrderWeightAllotment.TotalWeightSelf + if *payload.HasDependents { + expectedUpdatedOrderAuthorizedWeight = expectedOriginalOrderWeightAllotment.TotalWeightSelfPlusDependents + } + + suite.Equal(expectedUpdatedOrderAuthorizedWeight, 7000) // Ensure that when GetWeightAllotment is recalculated that it also returns 7000. This ensures that the database stored the correct information + suite.Equal(expectedOriginalOrderAuthorizedWeight, 5000) // The order was created as an E1. Ensure that the E1 authorized weight is 5000. + suite.Equal(string(newOrdersType), string(updatedOrder.OrdersType)) + // Check updated entitlement + var updatedEntitlement models.Entitlement + err = suite.DB().Find(&updatedEntitlement, updatedOrder.EntitlementID) + suite.NoError(err) + suite.NotEmpty(updatedEntitlement) + + suite.NotNil(updatedEntitlement.AccompaniedTour) + suite.NotNil(updatedEntitlement.DependentsTwelveAndOver) + suite.NotNil(updatedEntitlement.DependentsUnderTwelve) }) + } func (suite *HandlerSuite) TestUpdateOrdersHandlerOriginPostalCodeAndGBLOC() { diff --git a/pkg/handlers/primeapi/payloads/model_to_payload.go b/pkg/handlers/primeapi/payloads/model_to_payload.go index 8dc07ccaa32..af39f03827f 100644 --- a/pkg/handlers/primeapi/payloads/model_to_payload.go +++ b/pkg/handlers/primeapi/payloads/model_to_payload.go @@ -35,9 +35,11 @@ func MoveTaskOrder(appCtx appcontext.AppContext, moveTaskOrder *models.Move) *pr if err != nil { destGbloc = "" } - destZip, err = moveTaskOrder.GetDestinationPostalCode(db) + destinationAddress, err := moveTaskOrder.GetDestinationAddress(appCtx.DB()) if err != nil { destZip = "" + } else { + destZip = destinationAddress.PostalCode } payload := &primemessages.MoveTaskOrder{ @@ -92,9 +94,11 @@ func ListMove(move *models.Move, appCtx appcontext.AppContext, moveOrderAmendmen if err != nil { destGbloc = "" } - destZip, err = move.GetDestinationPostalCode(db) + destinationAddress, err := move.GetDestinationAddress(appCtx.DB()) if err != nil { destZip = "" + } else { + destZip = destinationAddress.PostalCode } payload := &primemessages.ListMove{ diff --git a/pkg/handlers/primeapiv2/payloads/model_to_payload.go b/pkg/handlers/primeapiv2/payloads/model_to_payload.go index 0950f80eafe..3a49ba8b5fb 100644 --- a/pkg/handlers/primeapiv2/payloads/model_to_payload.go +++ b/pkg/handlers/primeapiv2/payloads/model_to_payload.go @@ -32,9 +32,11 @@ func MoveTaskOrder(appCtx appcontext.AppContext, moveTaskOrder *models.Move) *pr if err != nil { destGbloc = "" } - destZip, err = moveTaskOrder.GetDestinationPostalCode(db) + destinationAddress, err := moveTaskOrder.GetDestinationAddress(appCtx.DB()) if err != nil { destZip = "" + } else { + destZip = destinationAddress.PostalCode } payload := &primev2messages.MoveTaskOrder{ diff --git a/pkg/handlers/primeapiv3/payloads/model_to_payload.go b/pkg/handlers/primeapiv3/payloads/model_to_payload.go index 4d6d51a9d23..d61f70f997c 100644 --- a/pkg/handlers/primeapiv3/payloads/model_to_payload.go +++ b/pkg/handlers/primeapiv3/payloads/model_to_payload.go @@ -35,9 +35,11 @@ func MoveTaskOrder(appCtx appcontext.AppContext, moveTaskOrder *models.Move) *pr if err != nil { destGbloc = "" } - destZip, err = moveTaskOrder.GetDestinationPostalCode(db) + destinationAddress, err := moveTaskOrder.GetDestinationAddress(appCtx.DB()) if err != nil { destZip = "" + } else { + destZip = destinationAddress.PostalCode } payload := &primev3messages.MoveTaskOrder{ diff --git a/pkg/models/address.go b/pkg/models/address.go index d89a163c9aa..29a6bedbcbb 100644 --- a/pkg/models/address.go +++ b/pkg/models/address.go @@ -211,3 +211,17 @@ func EvaluateIsOconus(address Address) bool { return false } } + +// Fetches the GBLOC for a specific Address (for now this will be used for OCONUS) +func FetchAddressGbloc(db *pop.Connection, address Address, serviceMember ServiceMember) (*string, error) { + var gbloc *string + + err := db.RawQuery("SELECT * FROM get_address_gbloc($1, $2)", address.ID, serviceMember.Affiliation.String()). + First(&gbloc) + + if err != nil { + return nil, err + } + + return gbloc, nil +} diff --git a/pkg/models/address_test.go b/pkg/models/address_test.go index f2fbb5bf45c..9dfe5a7fa1c 100644 --- a/pkg/models/address_test.go +++ b/pkg/models/address_test.go @@ -1,8 +1,13 @@ package models_test import ( + "fmt" + + "github.com/gofrs/uuid" + "github.com/transcom/mymove/pkg/factory" m "github.com/transcom/mymove/pkg/models" + "github.com/transcom/mymove/pkg/testdatagen" ) func (suite *ModelSuite) TestBasicAddressInstantiation() { @@ -190,3 +195,193 @@ func (suite *ModelSuite) TestPartialAddressFormat() { suite.Equal("street 1, city, state 90210", formattedAddress) } + +func (suite *ModelSuite) Test_FetchDutyLocationGblocForAK() { + setupDataForOconusDutyLocation := func(postalCode string) (m.OconusRateArea, m.UsPostRegionCity, m.DutyLocation) { + usprc, err := m.FindByZipCode(suite.AppContextForTest().DB(), postalCode) + suite.NotNil(usprc) + suite.FatalNoError(err) + + address := factory.BuildAddress(suite.DB(), []factory.Customization{ + { + Model: m.Address{ + IsOconus: m.BoolPointer(true), + UsPostRegionCityID: &usprc.ID, + }, + }, + }, nil) + originDutyLocation := factory.BuildDutyLocation(suite.DB(), []factory.Customization{ + { + Model: address, + LinkOnly: true, + Type: &factory.Addresses.DutyLocationAddress, + }, + }, nil) + + contract := testdatagen.FetchOrMakeReContract(suite.DB(), testdatagen.Assertions{}) + + rateAreaCode := uuid.Must(uuid.NewV4()).String()[0:5] + rateArea := testdatagen.FetchOrMakeReRateArea(suite.DB(), testdatagen.Assertions{ + ReRateArea: m.ReRateArea{ + ContractID: contract.ID, + IsOconus: true, + Name: fmt.Sprintf("Alaska-%s", rateAreaCode), + Contract: contract, + }, + }) + suite.NotNil(rateArea) + suite.Nil(err) + + us_country, err := m.FetchCountryByCode(suite.DB(), "US") + suite.NotNil(us_country) + suite.Nil(err) + + oconusRateArea, err := m.FetchOconusRateAreaByCityId(suite.DB(), usprc.ID.String()) + suite.NotNil(oconusRateArea) + suite.Nil(err) + + return *oconusRateArea, *usprc, originDutyLocation + } + + suite.Run("fetches duty location GBLOC for AK address, Zone II AirForce", func() { + oconusRateArea, _, originDutyLocation := setupDataForOconusDutyLocation("99707") + + airForce := m.AffiliationAIRFORCE + serviceMember := factory.BuildServiceMember(suite.DB(), []factory.Customization{ + { + Model: m.ServiceMember{ + Affiliation: &airForce, + }, + }, + }, nil) + + jppsoRegion, err := m.FetchJppsoRegionByCode(suite.DB(), "MBFL") + suite.NotNil(jppsoRegion) + suite.Nil(err) + + gblocAors, err := m.FetchGblocAorsByJppsoCodeRateAreaDept(suite.DB(), jppsoRegion.ID, oconusRateArea.ID, m.DepartmentIndicatorAIRANDSPACEFORCE.String()) + suite.NotNil(gblocAors) + suite.Nil(err) + + gbloc, err := m.FetchAddressGbloc(suite.DB(), originDutyLocation.Address, serviceMember) + suite.NoError(err) + suite.NotNil(gbloc) + suite.Equal(string(*gbloc), "MBFL") + }) + + suite.Run("fetches duty location GBLOC for AK address, Zone II Army", func() { + oconusRateArea, _, originDutyLocation := setupDataForOconusDutyLocation("99707") + + army := m.AffiliationARMY + serviceMember := factory.BuildServiceMember(suite.DB(), []factory.Customization{ + { + Model: m.ServiceMember{ + Affiliation: &army, + }, + }, + }, nil) + + jppsoRegion, err := m.FetchJppsoRegionByCode(suite.DB(), "JEAT") + suite.NotNil(jppsoRegion) + suite.Nil(err) + + gblocAors, err := m.FetchGblocAorsByJppsoCodeRateAreaDept(suite.DB(), jppsoRegion.ID, oconusRateArea.ID, m.DepartmentIndicatorARMY.String()) + suite.NotNil(gblocAors) + suite.Nil(err) + + gbloc, err := m.FetchAddressGbloc(suite.DB(), originDutyLocation.Address, serviceMember) + suite.NoError(err) + suite.NotNil(gbloc) + suite.Equal(string(*gbloc), "JEAT") + }) + + suite.Run("fetches duty location GBLOC for AK Cordova address, Zone IV", func() { + usprc, err := m.FindByZipCodeAndCity(suite.AppContextForTest().DB(), "99574", "CORDOVA") + suite.NotNil(usprc) + suite.FatalNoError(err) + + address := factory.BuildAddress(suite.DB(), []factory.Customization{ + { + Model: m.Address{ + IsOconus: m.BoolPointer(true), + UsPostRegionCityID: &usprc.ID, + }, + }, + }, nil) + originDutyLocation := factory.BuildDutyLocation(suite.DB(), []factory.Customization{ + { + Model: address, + LinkOnly: true, + Type: &factory.Addresses.DutyLocationAddress, + }, + }, nil) + + contract := testdatagen.FetchOrMakeReContract(suite.DB(), testdatagen.Assertions{}) + + rateAreaCode := uuid.Must(uuid.NewV4()).String()[0:5] + rateArea := testdatagen.FetchOrMakeReRateArea(suite.DB(), testdatagen.Assertions{ + ReRateArea: m.ReRateArea{ + ContractID: contract.ID, + IsOconus: true, + Name: fmt.Sprintf("Alaska-%s", rateAreaCode), + Contract: contract, + }, + }) + suite.NotNil(rateArea) + + us_country, err := m.FetchCountryByCode(suite.DB(), "US") + suite.NotNil(us_country) + suite.Nil(err) + + oconusRateArea, err := m.FetchOconusRateAreaByCityId(suite.DB(), usprc.ID.String()) + suite.NotNil(oconusRateArea) + suite.Nil(err) + army := m.AffiliationARMY + serviceMember := factory.BuildServiceMember(suite.DB(), []factory.Customization{ + { + Model: m.ServiceMember{ + Affiliation: &army, + }, + }, + }, nil) + + jppsoRegion, err := m.FetchJppsoRegionByCode(suite.DB(), "MAPS") + suite.NotNil(jppsoRegion) + suite.Nil(err) + + gblocAors, err := m.FetchGblocAorsByJppsoCodeRateAreaDept(suite.DB(), jppsoRegion.ID, oconusRateArea.ID, m.DepartmentIndicatorARMY.String()) + suite.NotNil(gblocAors) + suite.Nil(err) + + gbloc, err := m.FetchAddressGbloc(suite.DB(), originDutyLocation.Address, serviceMember) + suite.NoError(err) + suite.NotNil(gbloc) + suite.Equal(string(*gbloc), "MAPS") + }) + + suite.Run("fetches duty location GBLOC for AK NOT Cordova address, Zone IV", func() { + oconusRateArea, _, originDutyLocation := setupDataForOconusDutyLocation("99803") + + army := m.AffiliationARMY + serviceMember := factory.BuildServiceMember(suite.DB(), []factory.Customization{ + { + Model: m.ServiceMember{ + Affiliation: &army, + }, + }, + }, nil) + + jppsoRegion, err := m.FetchJppsoRegionByCode(suite.DB(), "MAPK") + suite.NotNil(jppsoRegion) + suite.Nil(err) + + gblocAors, err := m.FetchGblocAorsByJppsoCodeRateAreaDept(suite.DB(), jppsoRegion.ID, oconusRateArea.ID, m.DepartmentIndicatorARMY.String()) + suite.NotNil(gblocAors) + suite.Nil(err) + + gbloc, err := m.FetchAddressGbloc(suite.DB(), originDutyLocation.Address, serviceMember) + suite.NoError(err) + suite.NotNil(gbloc) + suite.Equal(string(*gbloc), "MAPK") + }) +} diff --git a/pkg/models/gbloc_aors.go b/pkg/models/gbloc_aors.go index e4fa1612355..132de00bbb1 100644 --- a/pkg/models/gbloc_aors.go +++ b/pkg/models/gbloc_aors.go @@ -3,6 +3,7 @@ package models import ( "time" + "github.com/gobuffalo/pop/v6" "github.com/gofrs/uuid" ) @@ -19,3 +20,17 @@ type GblocAors struct { func (c GblocAors) TableName() string { return "gbloc_aors" } + +func FetchGblocAorsByJppsoCodeRateAreaDept(db *pop.Connection, jppsoRegionId uuid.UUID, oconusRateAreaId uuid.UUID, deptInd string) (*GblocAors, error) { + var gblocAors GblocAors + err := db.Q(). + InnerJoin("jppso_regions jr", "gbloc_aors.jppso_regions_id = jr.id"). + Where("gbloc_aors.oconus_rate_area_id = ?", oconusRateAreaId). + Where("(gbloc_aors.department_indicator = ? or gbloc_aors.department_indicator is null)", deptInd). + Where("jr.id = ?", jppsoRegionId). + First(&gblocAors) + if err != nil { + return nil, err + } + return &gblocAors, nil +} diff --git a/pkg/models/gbloc_aors_test.go b/pkg/models/gbloc_aors_test.go new file mode 100644 index 00000000000..7e35492e58a --- /dev/null +++ b/pkg/models/gbloc_aors_test.go @@ -0,0 +1,22 @@ +package models_test + +import ( + "github.com/transcom/mymove/pkg/models" +) + +func (suite *ModelSuite) TestFetchGblocAorsByJppsoCodeRateAreaDept() { + usprc, err := models.FindByZipCode(suite.AppContextForTest().DB(), "99801") + suite.NotNil(usprc) + suite.FatalNoError(err) + oconusRateArea, err := models.FetchOconusRateAreaByCityId(suite.DB(), usprc.ID.String()) + suite.NotNil(oconusRateArea) + suite.NoError(err) + + jppsoRegion, err := models.FetchJppsoRegionByCode(suite.DB(), "MAPK") + suite.NotNil(jppsoRegion) + suite.NoError(err) + + gblocAors, err := models.FetchGblocAorsByJppsoCodeRateAreaDept(suite.DB(), jppsoRegion.ID, oconusRateArea.ID, models.DepartmentIndicatorARMY.String()) + suite.NotNil(gblocAors) + suite.NoError(err) +} diff --git a/pkg/models/jppso_regions.go b/pkg/models/jppso_regions.go index 0788c78abb2..aefb3ea106f 100644 --- a/pkg/models/jppso_regions.go +++ b/pkg/models/jppso_regions.go @@ -3,6 +3,7 @@ package models import ( "time" + "github.com/gobuffalo/pop/v6" "github.com/gofrs/uuid" ) @@ -18,3 +19,14 @@ type JppsoRegions struct { func (c JppsoRegions) TableName() string { return "jppso_regions" } + +func FetchJppsoRegionByCode(db *pop.Connection, code string) (*JppsoRegions, error) { + var jppsoRegions JppsoRegions + err := db.Q(). + Where("jppso_regions.code = ?", code). + First(&jppsoRegions) + if err != nil { + return nil, err + } + return &jppsoRegions, nil +} diff --git a/pkg/models/jppso_regions_test.go b/pkg/models/jppso_regions_test.go new file mode 100644 index 00000000000..21da54ea898 --- /dev/null +++ b/pkg/models/jppso_regions_test.go @@ -0,0 +1,12 @@ +package models_test + +import ( + "github.com/transcom/mymove/pkg/models" +) + +func (suite *ModelSuite) TestFetchJppsoRegionByCode() { + jppsoRegion, err := models.FetchJppsoRegionByCode(suite.DB(), "MAPK") + suite.NotNil(jppsoRegion) + suite.NoError(err) + suite.Equal("USCG Base Ketchikan", jppsoRegion.Name) +} diff --git a/pkg/models/move.go b/pkg/models/move.go index f0b3ac49269..c84068b47ef 100644 --- a/pkg/models/move.go +++ b/pkg/models/move.go @@ -71,7 +71,7 @@ type Move struct { PPMType *string `db:"ppm_type"` MTOServiceItems MTOServiceItems `has_many:"mto_service_items" fk_id:"move_id"` PaymentRequests PaymentRequests `has_many:"payment_requests" fk_id:"move_id"` - MTOShipments MTOShipments `has_many:"mto_shipments" fk_id:"move_id"` + MTOShipments MTOShipments `json:"mto_shipments" has_many:"mto_shipments" fk_id:"move_id"` ReferenceID *string `db:"reference_id"` ServiceCounselingCompletedAt *time.Time `db:"service_counseling_completed_at"` PrimeCounselingCompletedAt *time.Time `db:"prime_counseling_completed_at"` @@ -98,11 +98,11 @@ type Move struct { SCAssignedID *uuid.UUID `json:"sc_assigned_id" db:"sc_assigned_id"` SCAssignedUser *OfficeUser `belongs_to:"office_users" fk_id:"sc_assigned_id"` TOOAssignedID *uuid.UUID `json:"too_assigned_id" db:"too_assigned_id"` - TOOAssignedUser *OfficeUser `belongs_to:"office_users" fk_id:"too_assigned_id"` + TOOAssignedUser *OfficeUser `json:"too_assigned" belongs_to:"office_users" fk_id:"too_assigned_id"` TIOAssignedID *uuid.UUID `json:"tio_assigned_id" db:"tio_assigned_id"` TIOAssignedUser *OfficeUser `belongs_to:"office_users" fk_id:"tio_assigned_id"` CounselingOfficeID *uuid.UUID `json:"counseling_transportation_office_id" db:"counseling_transportation_office_id"` - CounselingOffice *TransportationOffice `belongs_to:"transportation_offices" fk_id:"counseling_transportation_office_id"` + CounselingOffice *TransportationOffice `json:"counseling_transportation_office" belongs_to:"transportation_offices" fk_id:"counseling_transportation_office_id"` } type MoveWithEarliestDate struct { @@ -203,48 +203,63 @@ func FetchMove(db *pop.Connection, session *auth.Session, id uuid.UUID) (*Move, return &move, nil } -// GetDestinationPostalCode returns the postal code for the move. This ensures that business logic is centralized. -func (m Move) GetDestinationPostalCode(db *pop.Connection) (string, error) { +// GetDestinationGBLOC returns the GBLOC for the move. This ensures that business logic is centralized. +func (m Move) GetDestinationGBLOC(db *pop.Connection) (string, error) { // Since this requires looking up the move in the DB, the move must have an ID. This means, the move has to have been created first. if uuid.UUID.IsNil(m.ID) { - return "", errors.WithMessage(ErrInvalidOrderID, "You must created the move in the DB before getting the destination Postal Code.") + return "", errors.WithMessage(ErrInvalidOrderID, "You must created the move in the DB before getting the destination GBLOC.") } - err := db.Load(&m, "Orders") + destinationAddress, err := m.GetDestinationAddress(db) if err != nil { - if err.Error() == RecordNotFoundErrorString { - return "", errors.WithMessage(err, "No Orders found in the DB associated with moveID "+m.ID.String()) - } return "", err } - var gblocsMap map[uuid.UUID]string - gblocsMap, err = m.Orders.GetDestinationPostalCodeForAssociatedMoves(db) - if err != nil { - return "", err + var newGBLOC string + if *destinationAddress.IsOconus { + err := db.Load(&m.Orders, "ServiceMember") + if err != nil { + if err.Error() == RecordNotFoundErrorString { + return "", errors.WithMessage(err, "No Service Member found in the DB associated with moveID "+m.ID.String()) + } + return "", err + } + newGBLOCOconus, err := FetchAddressGbloc(db, *destinationAddress, m.Orders.ServiceMember) + if err != nil { + return "", err + } + newGBLOC = *newGBLOCOconus + } else { + newGBLOCConus, err := FetchGBLOCForPostalCode(db, destinationAddress.PostalCode) + if err != nil { + return "", err + } + newGBLOC = newGBLOCConus.GBLOC } - return gblocsMap[m.ID], nil + + return newGBLOC, err } -// GetDestinationGBLOC returns the GBLOC for the move. This ensures that business logic is centralized. -func (m Move) GetDestinationGBLOC(db *pop.Connection) (string, error) { +// GetDestinationAddress returns the address for the move. This ensures that business logic is centralized. +func (m Move) GetDestinationAddress(db *pop.Connection) (*Address, error) { // Since this requires looking up the move in the DB, the move must have an ID. This means, the move has to have been created first. if uuid.UUID.IsNil(m.ID) { - return "", errors.WithMessage(ErrInvalidOrderID, "You must created the move in the DB before getting the destination GBLOC.") + return nil, errors.WithMessage(ErrInvalidOrderID, "You must created the move in the DB before getting the destination Postal Code.") } - postalCode, err := m.GetDestinationPostalCode(db) + err := db.Load(&m, "Orders") if err != nil { - return "", err + if err.Error() == RecordNotFoundErrorString { + return nil, errors.WithMessage(err, "No Orders found in the DB associated with moveID "+m.ID.String()) + } + return nil, err } - var gblocResult PostalCodeToGBLOC - gblocResult, err = FetchGBLOCForPostalCode(db, postalCode) + destinationAddress, err := m.Orders.GetDestinationAddressForAssociatedMoves(db) if err != nil { - return "", err + return nil, err } - - return gblocResult.GBLOC, err + return destinationAddress, nil } // CreateSignedCertification creates a new SignedCertification associated with this move diff --git a/pkg/models/mto_shipments.go b/pkg/models/mto_shipments.go index 66db8cb78d2..148f1130e65 100644 --- a/pkg/models/mto_shipments.go +++ b/pkg/models/mto_shipments.go @@ -118,74 +118,74 @@ const ( // MTOShipment is an object representing data for a move task order shipment type MTOShipment struct { - ID uuid.UUID `db:"id"` - MoveTaskOrder Move `belongs_to:"moves" fk_id:"move_id"` - MoveTaskOrderID uuid.UUID `db:"move_id"` - ScheduledPickupDate *time.Time `db:"scheduled_pickup_date"` - RequestedPickupDate *time.Time `db:"requested_pickup_date"` - RequestedDeliveryDate *time.Time `db:"requested_delivery_date"` - ApprovedDate *time.Time `db:"approved_date"` - FirstAvailableDeliveryDate *time.Time `db:"first_available_delivery_date"` - ActualPickupDate *time.Time `db:"actual_pickup_date"` - RequiredDeliveryDate *time.Time `db:"required_delivery_date"` - ScheduledDeliveryDate *time.Time `db:"scheduled_delivery_date"` - ActualDeliveryDate *time.Time `db:"actual_delivery_date"` - CustomerRemarks *string `db:"customer_remarks"` - CounselorRemarks *string `db:"counselor_remarks"` - PickupAddress *Address `belongs_to:"addresses" fk_id:"pickup_address_id"` - PickupAddressID *uuid.UUID `db:"pickup_address_id"` - DestinationAddress *Address `belongs_to:"addresses" fk_id:"destination_address_id"` - DestinationAddressID *uuid.UUID `db:"destination_address_id"` - DestinationType *DestinationType `db:"destination_address_type"` - MTOAgents MTOAgents `has_many:"mto_agents" fk_id:"mto_shipment_id"` - MTOServiceItems MTOServiceItems `has_many:"mto_service_items" fk_id:"mto_shipment_id"` - SecondaryPickupAddress *Address `belongs_to:"addresses" fk_id:"secondary_pickup_address_id"` - SecondaryPickupAddressID *uuid.UUID `db:"secondary_pickup_address_id"` - HasSecondaryPickupAddress *bool `db:"has_secondary_pickup_address"` - SecondaryDeliveryAddress *Address `belongs_to:"addresses" fk_id:"secondary_delivery_address_id"` - SecondaryDeliveryAddressID *uuid.UUID `db:"secondary_delivery_address_id"` - HasSecondaryDeliveryAddress *bool `db:"has_secondary_delivery_address"` - TertiaryPickupAddress *Address `belongs_to:"addresses" fk_id:"tertiary_pickup_address_id"` - TertiaryPickupAddressID *uuid.UUID `db:"tertiary_pickup_address_id"` - HasTertiaryPickupAddress *bool `db:"has_tertiary_pickup_address"` - TertiaryDeliveryAddress *Address `belongs_to:"addresses" fk_id:"tertiary_delivery_address_id"` - TertiaryDeliveryAddressID *uuid.UUID `db:"tertiary_delivery_address_id"` - HasTertiaryDeliveryAddress *bool `db:"has_tertiary_delivery_address"` - SITDaysAllowance *int `db:"sit_days_allowance"` - SITDurationUpdates SITDurationUpdates `has_many:"sit_extensions" fk_id:"mto_shipment_id"` - PrimeEstimatedWeight *unit.Pound `db:"prime_estimated_weight"` - PrimeEstimatedWeightRecordedDate *time.Time `db:"prime_estimated_weight_recorded_date"` - PrimeActualWeight *unit.Pound `db:"prime_actual_weight"` - BillableWeightCap *unit.Pound `db:"billable_weight_cap"` - BillableWeightJustification *string `db:"billable_weight_justification"` - NTSRecordedWeight *unit.Pound `db:"nts_recorded_weight"` - ShipmentType MTOShipmentType `db:"shipment_type"` - Status MTOShipmentStatus `db:"status"` - Diversion bool `db:"diversion"` - DiversionReason *string `db:"diversion_reason"` - DivertedFromShipmentID *uuid.UUID `db:"diverted_from_shipment_id"` - ActualProGearWeight *unit.Pound `db:"actual_pro_gear_weight"` - ActualSpouseProGearWeight *unit.Pound `db:"actual_spouse_pro_gear_weight"` - RejectionReason *string `db:"rejection_reason"` - Distance *unit.Miles `db:"distance"` - Reweigh *Reweigh `has_one:"reweighs" fk_id:"shipment_id"` - UsesExternalVendor bool `db:"uses_external_vendor"` - StorageFacility *StorageFacility `belongs_to:"storage_facilities" fk:"storage_facility_id"` - StorageFacilityID *uuid.UUID `db:"storage_facility_id"` - ServiceOrderNumber *string `db:"service_order_number"` - TACType *LOAType `db:"tac_type"` - SACType *LOAType `db:"sac_type"` - PPMShipment *PPMShipment `has_one:"ppm_shipment" fk_id:"shipment_id"` - BoatShipment *BoatShipment `has_one:"boat_shipment" fk_id:"shipment_id"` - DeliveryAddressUpdate *ShipmentAddressUpdate `has_one:"shipment_address_update" fk_id:"shipment_id"` - CreatedAt time.Time `db:"created_at"` - UpdatedAt time.Time `db:"updated_at"` - DeletedAt *time.Time `db:"deleted_at"` - ShipmentLocator *string `db:"shipment_locator"` - OriginSITAuthEndDate *time.Time `db:"origin_sit_auth_end_date"` - DestinationSITAuthEndDate *time.Time `db:"dest_sit_auth_end_date"` - MobileHome *MobileHome `has_one:"mobile_home" fk_id:"shipment_id"` - MarketCode MarketCode `db:"market_code"` + ID uuid.UUID `json:"id" db:"id"` + MoveTaskOrder Move `json:"move_task_order" belongs_to:"moves" fk_id:"move_id"` + MoveTaskOrderID uuid.UUID `json:"move_task_order_id" db:"move_id"` + ScheduledPickupDate *time.Time `json:"scheduled_pickup_date" db:"scheduled_pickup_date"` + RequestedPickupDate *time.Time `json:"requested_pickup_date" db:"requested_pickup_date"` + RequestedDeliveryDate *time.Time `json:"requested_delivery_date" db:"requested_delivery_date"` + ApprovedDate *time.Time `json:"approved_date" db:"approved_date"` + FirstAvailableDeliveryDate *time.Time `json:"first_available_delivery_date" db:"first_available_delivery_date"` + ActualPickupDate *time.Time `json:"actual_pickup_date" db:"actual_pickup_date"` + RequiredDeliveryDate *time.Time `json:"required_delivery_date" db:"required_delivery_date"` + ScheduledDeliveryDate *time.Time `json:"scheduled_delivery_date" db:"scheduled_delivery_date"` + ActualDeliveryDate *time.Time `json:"actual_delivery_date" db:"actual_delivery_date"` + CustomerRemarks *string `json:"customer_remarks" db:"customer_remarks"` + CounselorRemarks *string `json:"counselor_remarks" db:"counselor_remarks"` + PickupAddress *Address `json:"pickup_address" belongs_to:"addresses" fk_id:"pickup_address_id"` + PickupAddressID *uuid.UUID `json:"pickup_address_id" db:"pickup_address_id"` + DestinationAddress *Address `json:"destination_address" belongs_to:"addresses" fk_id:"destination_address_id"` + DestinationAddressID *uuid.UUID `json:"destination_address_id" db:"destination_address_id"` + DestinationType *DestinationType `json:"destination_type" db:"destination_address_type"` + MTOAgents MTOAgents `json:"mto_agents" has_many:"mto_agents" fk_id:"mto_shipment_id"` + MTOServiceItems MTOServiceItems `json:"mto_service_items" has_many:"mto_service_items" fk_id:"mto_shipment_id"` + SecondaryPickupAddress *Address `json:"secondary_pickup_address" belongs_to:"addresses" fk_id:"secondary_pickup_address_id"` + SecondaryPickupAddressID *uuid.UUID `json:"secondary_pickup_address_id" db:"secondary_pickup_address_id"` + HasSecondaryPickupAddress *bool `json:"has_secondary_pickup_address" db:"has_secondary_pickup_address"` + SecondaryDeliveryAddress *Address `json:"secondary_delivery_address" belongs_to:"addresses" fk_id:"secondary_delivery_address_id"` + SecondaryDeliveryAddressID *uuid.UUID `json:"secondary_delivery_address_id" db:"secondary_delivery_address_id"` + HasSecondaryDeliveryAddress *bool `json:"has_secondary_delivery_address" db:"has_secondary_delivery_address"` + TertiaryPickupAddress *Address `json:"tertiary_pickup_address" belongs_to:"addresses" fk_id:"tertiary_pickup_address_id"` + TertiaryPickupAddressID *uuid.UUID `json:"tertiary_pickup_address_id" db:"tertiary_pickup_address_id"` + HasTertiaryPickupAddress *bool `json:"has_tertiary_pickup_address" db:"has_tertiary_pickup_address"` + TertiaryDeliveryAddress *Address `json:"tertiary_delivery_address" belongs_to:"addresses" fk_id:"tertiary_delivery_address_id"` + TertiaryDeliveryAddressID *uuid.UUID `json:"tertiary_delivery_address_id" db:"tertiary_delivery_address_id"` + HasTertiaryDeliveryAddress *bool `json:"has_tertiary_delivery_address" db:"has_tertiary_delivery_address"` + SITDaysAllowance *int `json:"sit_days_allowance" db:"sit_days_allowance"` + SITDurationUpdates SITDurationUpdates `json:"sit_duration_updates" has_many:"sit_extensions" fk_id:"mto_shipment_id"` + PrimeEstimatedWeight *unit.Pound `json:"prime_estimated_weight" db:"prime_estimated_weight"` + PrimeEstimatedWeightRecordedDate *time.Time `json:"prime_estimated_weight_recorded_date" db:"prime_estimated_weight_recorded_date"` + PrimeActualWeight *unit.Pound `json:"prime_actual_weight" db:"prime_actual_weight"` + BillableWeightCap *unit.Pound `json:"billable_weight_cap" db:"billable_weight_cap"` + BillableWeightJustification *string `json:"billable_weight_justification" db:"billable_weight_justification"` + NTSRecordedWeight *unit.Pound `json:"nts_recorded_weight" db:"nts_recorded_weight"` + ShipmentType MTOShipmentType `json:"shipment_type" db:"shipment_type"` + Status MTOShipmentStatus `json:"status" db:"status"` + Diversion bool `json:"diversion" db:"diversion"` + DiversionReason *string `json:"diversion_reason" db:"diversion_reason"` + DivertedFromShipmentID *uuid.UUID `json:"diverted_from_shipment_id" db:"diverted_from_shipment_id"` + ActualProGearWeight *unit.Pound `json:"actual_pro_gear_weight" db:"actual_pro_gear_weight"` + ActualSpouseProGearWeight *unit.Pound `json:"actual_spouse_pro_gear_weight" db:"actual_spouse_pro_gear_weight"` + RejectionReason *string `json:"rejection_reason" db:"rejection_reason"` + Distance *unit.Miles `json:"distance" db:"distance"` + Reweigh *Reweigh `json:"reweigh" has_one:"reweighs" fk_id:"shipment_id"` + UsesExternalVendor bool `json:"uses_external_vendor" db:"uses_external_vendor"` + StorageFacility *StorageFacility `json:"storage_facility" belongs_to:"storage_facilities" fk:"storage_facility_id"` + StorageFacilityID *uuid.UUID `json:"storage_facility_id" db:"storage_facility_id"` + ServiceOrderNumber *string `json:"service_order_number" db:"service_order_number"` + TACType *LOAType `json:"tac_type" db:"tac_type"` + SACType *LOAType `json:"sac_type" db:"sac_type"` + PPMShipment *PPMShipment `json:"ppm_shipment" has_one:"ppm_shipment" fk_id:"shipment_id"` + BoatShipment *BoatShipment `json:"boat_shipment" has_one:"boat_shipment" fk_id:"shipment_id"` + DeliveryAddressUpdate *ShipmentAddressUpdate `json:"delivery_address_update" has_one:"shipment_address_update" fk_id:"shipment_id"` + CreatedAt time.Time `json:"created_at" db:"created_at"` + UpdatedAt time.Time `json:"updated_at" db:"updated_at"` + DeletedAt *time.Time `json:"deleted_at" db:"deleted_at"` + ShipmentLocator *string `json:"shipment_locator" db:"shipment_locator"` + OriginSITAuthEndDate *time.Time `json:"origin_sit_auth_end_date" db:"origin_sit_auth_end_date"` + DestinationSITAuthEndDate *time.Time `json:"destination_sit_auth_end_date" db:"dest_sit_auth_end_date"` + MobileHome *MobileHome `json:"mobile_home" has_one:"mobile_home" fk_id:"shipment_id"` + MarketCode MarketCode `json:"market_code" db:"market_code"` } // TableName overrides the table name used by Pop. @@ -294,33 +294,6 @@ func GetCustomerFromShipment(db *pop.Connection, shipmentID uuid.UUID) (*Service return &serviceMember, nil } -func (m *MTOShipment) UpdateOrdersDestinationGBLOC(db *pop.Connection) error { - // Since this requires looking up the order in the DB, the order must have an ID. This means, the order has to have been created first. - if uuid.UUID.IsNil(m.ID) { - return fmt.Errorf("error updating orders destination GBLOC for shipment due to no shipment ID provided") - } - - var err error - var order Order - - err = db.Load(&m, "MoveTaskOrder.OrdersID") - if err != nil { - return fmt.Errorf("error loading orders for shipment ID: %s with error %w", m.ID, err) - } - - order, err = FetchOrder(db, m.MoveTaskOrder.OrdersID) - if err != nil { - return fmt.Errorf("error fetching order for shipment ID: %s with error %w", m.ID, err) - } - - err = order.UpdateDestinationGBLOC(db) - if err != nil { - return fmt.Errorf("error fetching GBLOC for postal code with error %w", err) - } - - return nil -} - // Helper function to check that an MTO Shipment contains a PPM Shipment func (m MTOShipment) ContainsAPPMShipment() bool { return m.PPMShipment != nil diff --git a/pkg/models/order.go b/pkg/models/order.go index 476b96b1d43..a9120c9579f 100644 --- a/pkg/models/order.go +++ b/pkg/models/order.go @@ -70,14 +70,14 @@ type Order struct { CreatedAt time.Time `json:"created_at" db:"created_at"` UpdatedAt time.Time `json:"updated_at" db:"updated_at"` ServiceMemberID uuid.UUID `json:"service_member_id" db:"service_member_id"` - ServiceMember ServiceMember `belongs_to:"service_members" fk_id:"service_member_id"` + ServiceMember ServiceMember `json:"service_member" belongs_to:"service_members" fk_id:"service_member_id"` IssueDate time.Time `json:"issue_date" db:"issue_date"` ReportByDate time.Time `json:"report_by_date" db:"report_by_date"` OrdersType internalmessages.OrdersType `json:"orders_type" db:"orders_type"` OrdersTypeDetail *internalmessages.OrdersTypeDetail `json:"orders_type_detail" db:"orders_type_detail"` HasDependents bool `json:"has_dependents" db:"has_dependents"` SpouseHasProGear bool `json:"spouse_has_pro_gear" db:"spouse_has_pro_gear"` - OriginDutyLocation *DutyLocation `belongs_to:"duty_locations" fk_id:"origin_duty_location_id"` + OriginDutyLocation *DutyLocation `json:"origin_duty_location" belongs_to:"duty_locations" fk_id:"origin_duty_location_id"` OriginDutyLocationID *uuid.UUID `json:"origin_duty_location_id" db:"origin_duty_location_id"` NewDutyLocationID uuid.UUID `json:"new_duty_location_id" db:"new_duty_location_id"` NewDutyLocation DutyLocation `belongs_to:"duty_locations" fk_id:"new_duty_location_id"` @@ -482,45 +482,16 @@ func (o Order) FetchAllShipmentsExcludingRejected(db *pop.Connection) (map[uuid. } /* - * GetDestinationGBLOC returns a map of destination GBLOCs for the first shipments from all of - * the moves that are associated with an order. If there are no shipments returned on a particular move, - * it will return the GBLOC of the new duty station address for that move. - */ -func (o Order) GetDestinationGBLOC(db *pop.Connection) (map[uuid.UUID]string, error) { - // Since this requires looking up the order in the DB, the order must have an ID. This means, the order has to have been created first. - if uuid.UUID.IsNil(o.ID) { - return nil, errors.WithMessage(ErrInvalidOrderID, "You must created the order in the DB before getting the destination GBLOC.") - } - - destinationPostalCodesMap, err := o.GetDestinationPostalCodeForAssociatedMoves(db) - if err != nil { - return nil, err - } - - destinationGBLOCsMap := make(map[uuid.UUID]string) - for k, v := range destinationPostalCodesMap { - var gblocResult PostalCodeToGBLOC - gblocResult, err = FetchGBLOCForPostalCode(db, v) - if err != nil { - return nil, errors.WithMessage(err, "Could not get GBLOC for postal code "+v+" for move ID "+k.String()) - } - destinationGBLOCsMap[k] = gblocResult.GBLOC - } - - return destinationGBLOCsMap, nil -} - -/* -* GetDestinationPostalCodeForAssociatedMove returns a map of Postal Codes of the destination address for the first shipments from each of +* GetDestinationAddressForAssociatedMoves returns the destination Address for the first shipments from each of * the moves that are associated with an order. If there are no shipments returned, it will return the -* Postal Code of the new duty station addresses. +* Address of the new duty station addresses. */ -func (o Order) GetDestinationPostalCodeForAssociatedMoves(db *pop.Connection) (map[uuid.UUID]string, error) { +func (o Order) GetDestinationAddressForAssociatedMoves(db *pop.Connection) (*Address, error) { if uuid.UUID.IsNil(o.ID) { - return nil, errors.WithMessage(ErrInvalidOrderID, "You must created the order in the DB before getting the destination Postal Code.") + return nil, errors.WithMessage(ErrInvalidOrderID, "You must create the order in the DB before getting the destination Address.") } - err := db.Load(&o, "Moves", "NewDutyLocation.Address.PostalCode") + err := db.Load(&o, "Moves", "NewDutyLocation.Address") if err != nil { if err.Error() == RecordNotFoundErrorString { return nil, errors.WithMessage(err, "No Moves were found for the order ID "+o.ID.String()) @@ -528,8 +499,8 @@ func (o Order) GetDestinationPostalCodeForAssociatedMoves(db *pop.Connection) (m return nil, err } - // zipsMap is a map of key, value pairs where the key is the move id and the value is the destination postal code - zipsMap := make(map[uuid.UUID]string) + // addrMap is a map of key, value pairs where the key is the move id and the value is the destination address + var destinationAddress Address for i, m := range o.Moves { err = db.Load(&o.Moves[i], "MTOShipments") if err != nil { @@ -563,71 +534,23 @@ func (o Order) GetDestinationPostalCodeForAssociatedMoves(db *pop.Connection) (m return shipments[i].CreatedAt.Before(shipments[j].CreatedAt) }) - var addressResult *Address - addressResult, err = shipments[0].GetDestinationAddress(db) + addressResult, err := shipments[0].GetDestinationAddress(db) if err != nil { - if err == ErrMissingDestinationAddress || err == ErrUnsupportedShipmentType { - zipsMap[o.Moves[i].ID] = o.NewDutyLocation.Address.PostalCode - } return nil, err } if addressResult != nil { - zipsMap[o.Moves[i].ID] = addressResult.PostalCode + destinationAddress = *addressResult } else { return nil, errors.WithMessage(ErrMissingDestinationAddress, "No destination address was able to be found for the order ID "+o.ID.String()) } } else { // No valid shipments, use new duty location - zipsMap[o.Moves[i].ID] = o.NewDutyLocation.Address.PostalCode + destinationAddress = o.NewDutyLocation.Address } } - if len(zipsMap) == 0 { - return nil, errors.New("No destination postal codes were found for the order ID " + o.ID.String()) - } - - return zipsMap, nil -} - -// UpdateDestinationGBLOC updates the destination GBLOC for the associated Order in the DB -func (o Order) UpdateDestinationGBLOC(db *pop.Connection) error { - // Since this requires looking up the order in the DB, the order must have an ID. This means, the order has to have been created first. - if uuid.UUID.IsNil(o.ID) { - return errors.WithMessage(ErrInvalidOrderID, "You must created the order in the DB before updating the destination GBLOC.") - } - - var dbOrder Order - err := db.Find(&dbOrder, o.ID) - if err != nil { - if err.Error() == RecordNotFoundErrorString { - return errors.WithMessage(err, "No Order was found for the order ID "+o.ID.String()) - } - return err - } - - err = db.Load(&o, "NewDutyLocation.Address.PostalCode") - if err != nil { - if err.Error() == RecordNotFoundErrorString { - return errors.WithMessage(err, "No New Duty Location Address Postal Code was found for the order ID "+o.ID.String()) - } - return err - } - - var gblocResult PostalCodeToGBLOC - gblocResult, err = FetchGBLOCForPostalCode(db, o.NewDutyLocation.Address.PostalCode) - if err != nil { - return errors.WithMessage(err, "Could not get GBLOC for postal code "+o.NewDutyLocation.Address.PostalCode) - } - - dbOrder.DestinationGBLOC = &gblocResult.GBLOC - - err = db.Save(&dbOrder) - if err != nil { - return errors.WithMessage(err, "Could not save the updated destination GBLOC for order ID "+o.ID.String()) - } - - return nil + return &destinationAddress, nil } // IsCompleteForGBL checks if orders have all fields necessary to generate a GBL diff --git a/pkg/models/re_oconus_rate_areas.go b/pkg/models/re_oconus_rate_areas.go index 84def705f95..7003219ba9b 100644 --- a/pkg/models/re_oconus_rate_areas.go +++ b/pkg/models/re_oconus_rate_areas.go @@ -33,3 +33,14 @@ func FetchOconusRateArea(db *pop.Connection, zip string) (*OconusRateArea, error } return &reOconusRateArea, nil } + +func FetchOconusRateAreaByCityId(db *pop.Connection, usprc string) (*OconusRateArea, error) { + var reOconusRateArea OconusRateArea + err := db.Q(). + Where("re_oconus_rate_areas.us_post_region_cities_id = ?", usprc). + First(&reOconusRateArea) + if err != nil { + return nil, err + } + return &reOconusRateArea, nil +} diff --git a/pkg/models/re_oconus_rate_areas_test.go b/pkg/models/re_oconus_rate_areas_test.go new file mode 100644 index 00000000000..366bcff7daf --- /dev/null +++ b/pkg/models/re_oconus_rate_areas_test.go @@ -0,0 +1,14 @@ +package models_test + +import ( + "github.com/transcom/mymove/pkg/models" +) + +func (suite *ModelSuite) TestFetchOconusRateAreaByCityId() { + usprc, err := models.FindByZipCode(suite.AppContextForTest().DB(), "99801") + suite.NotNil(usprc) + suite.FatalNoError(err) + oconusRateArea, err := models.FetchOconusRateAreaByCityId(suite.DB(), usprc.ID.String()) + suite.NotNil(oconusRateArea) + suite.NoError(err) +} diff --git a/pkg/models/us_post_region_city.go b/pkg/models/us_post_region_city.go index 84e9a01941c..7267134f044 100644 --- a/pkg/models/us_post_region_city.go +++ b/pkg/models/us_post_region_city.go @@ -76,3 +76,19 @@ func FindByZipCode(db *pop.Connection, zipCode string) (*UsPostRegionCity, error } return &usprc, nil } + +func FindByZipCodeAndCity(db *pop.Connection, zipCode string, city string) (*UsPostRegionCity, error) { + var usprc UsPostRegionCity + err := db.Where("uspr_zip_id = ?", zipCode). + Where("u_s_post_region_city_nm = ?", city). + First(&usprc) + if err != nil { + switch err { + case sql.ErrNoRows: + return nil, apperror.NewEventError("No UsPostRegionCity found for provided zip code "+zipCode+" and city "+city+".", err) + default: + return nil, err + } + } + return &usprc, nil +} diff --git a/pkg/models/us_post_region_city_test.go b/pkg/models/us_post_region_city_test.go index 1654d1a817e..abadd9cdfe6 100644 --- a/pkg/models/us_post_region_city_test.go +++ b/pkg/models/us_post_region_city_test.go @@ -26,3 +26,12 @@ func (suite *ModelSuite) TestFindByZipCode() { suite.NoError(err) suite.Equal("LOS ANGELES", usPostRegionCity.UsprcCountyNm) } + +func (suite *ModelSuite) TestFindByZipCodeAndCity() { + + // Attempt to gather 99677's County from the 99677 zip code and CORDOVA city + usPostRegionCity, err := models.FindByZipCodeAndCity(suite.DB(), "99677", "CORDOVA") + suite.NotNil(usPostRegionCity) + suite.NoError(err) + suite.Equal("CHUGACH", usPostRegionCity.UsprcCountyNm) +} diff --git a/pkg/services/invoice/ghc_payment_request_invoice_generator.go b/pkg/services/invoice/ghc_payment_request_invoice_generator.go index fd111048868..4af73b9e28d 100644 --- a/pkg/services/invoice/ghc_payment_request_invoice_generator.go +++ b/pkg/services/invoice/ghc_payment_request_invoice_generator.go @@ -447,16 +447,26 @@ func (g ghcPaymentRequestInvoiceGenerator) createBuyerAndSellerOrganizationNames return apperror.NewQueryError("MTOShipments", err, fmt.Sprintf("error querying for shipments pickup address gbloc to use in N1*BY segments in PaymentRequest %s: %s", paymentRequestID, err)) } } - pickupPostalCodeToGbloc, gblocErr := models.FetchGBLOCForPostalCode(appCtx.DB(), address.PostalCode) - if gblocErr != nil { - return apperror.NewInvalidInputError(pickupPostalCodeToGbloc.ID, gblocErr, nil, "unable to determine GBLOC for pickup postal code") + var pickupPostalCodeToGbloc *string + if *address.IsOconus { + originDutyLocationGBLOCOconus, gblocErr := models.FetchAddressGbloc(appCtx.DB(), address, orders.ServiceMember) + if gblocErr != nil { + return apperror.NewInvalidInputError(address.ID, gblocErr, nil, "unable to determine GBLOC for Oconus pickup postal code") + } + pickupPostalCodeToGbloc = originDutyLocationGBLOCOconus + } else { + originDutyLocationGBLOCConus, gblocErr := models.FetchGBLOCForPostalCode(appCtx.DB(), originDutyLocation.Address.PostalCode) + if gblocErr != nil { + return apperror.NewInvalidInputError(address.ID, gblocErr, nil, "unable to determine GBLOC for pickup postal code") + } + pickupPostalCodeToGbloc = &originDutyLocationGBLOCConus.GBLOC } header.BuyerOrganizationName = edisegment.N1{ EntityIdentifierCode: "BY", Name: truncateStr(originDutyLocation.Name, maxLocationlength), IdentificationCodeQualifier: "92", - IdentificationCode: modifyGblocIfMarines(*orders.ServiceMember.Affiliation, pickupPostalCodeToGbloc.GBLOC), + IdentificationCode: modifyGblocIfMarines(*orders.ServiceMember.Affiliation, *pickupPostalCodeToGbloc), } // seller organization name @@ -482,9 +492,19 @@ func (g ghcPaymentRequestInvoiceGenerator) createOriginAndDestinationSegments(ap return apperror.NewConflictError(orders.ID, "Invalid Order, must have NewDutyLocation") } - destPostalCodeToGbloc, gblocErr := models.FetchGBLOCForPostalCode(appCtx.DB(), destinationDutyLocation.Address.PostalCode) - if gblocErr != nil { - return apperror.NewInvalidInputError(destinationDutyLocation.ID, gblocErr, nil, "unable to determine GBLOC for duty location postal code") + var destPostalCodeToGbloc *string + if *destinationDutyLocation.Address.IsOconus { + destPostalCodeToGblocOconus, gblocErr := models.FetchAddressGbloc(appCtx.DB(), destinationDutyLocation.Address, orders.ServiceMember) + if gblocErr != nil { + return apperror.NewInvalidInputError(destinationDutyLocation.ID, gblocErr, nil, "unable to determine GBLOC for Oconus duty location postal code") + } + destPostalCodeToGbloc = destPostalCodeToGblocOconus + } else { + ddestPostalCodeToGblocConus, gblocErr := models.FetchGBLOCForPostalCode(appCtx.DB(), destinationDutyLocation.Address.PostalCode) + if gblocErr != nil { + return apperror.NewInvalidInputError(destinationDutyLocation.ID, gblocErr, nil, "unable to determine GBLOC for duty location postal code") + } + destPostalCodeToGbloc = &ddestPostalCodeToGblocConus.GBLOC } // destination name @@ -492,7 +512,7 @@ func (g ghcPaymentRequestInvoiceGenerator) createOriginAndDestinationSegments(ap EntityIdentifierCode: "ST", Name: truncateStr(destinationDutyLocation.Name, maxLocationlength), IdentificationCodeQualifier: "10", - IdentificationCode: modifyGblocIfMarines(*orders.ServiceMember.Affiliation, destPostalCodeToGbloc.GBLOC), + IdentificationCode: modifyGblocIfMarines(*orders.ServiceMember.Affiliation, *destPostalCodeToGbloc), } // destination address diff --git a/pkg/services/mocks/OrderFetcher.go b/pkg/services/mocks/OrderFetcher.go index c7eb39d01ce..012df5ccb1b 100644 --- a/pkg/services/mocks/OrderFetcher.go +++ b/pkg/services/mocks/OrderFetcher.go @@ -80,6 +80,43 @@ func (_m *OrderFetcher) ListAllOrderLocations(appCtx appcontext.AppContext, offi return r0, r1 } +// ListDestinationRequestsOrders provides a mock function with given fields: appCtx, officeUserID, role, params +func (_m *OrderFetcher) ListDestinationRequestsOrders(appCtx appcontext.AppContext, officeUserID uuid.UUID, role roles.RoleType, params *services.ListOrderParams) ([]models.Move, int, error) { + ret := _m.Called(appCtx, officeUserID, role, params) + + if len(ret) == 0 { + panic("no return value specified for ListDestinationRequestsOrders") + } + + var r0 []models.Move + var r1 int + var r2 error + if rf, ok := ret.Get(0).(func(appcontext.AppContext, uuid.UUID, roles.RoleType, *services.ListOrderParams) ([]models.Move, int, error)); ok { + return rf(appCtx, officeUserID, role, params) + } + if rf, ok := ret.Get(0).(func(appcontext.AppContext, uuid.UUID, roles.RoleType, *services.ListOrderParams) []models.Move); ok { + r0 = rf(appCtx, officeUserID, role, params) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]models.Move) + } + } + + if rf, ok := ret.Get(1).(func(appcontext.AppContext, uuid.UUID, roles.RoleType, *services.ListOrderParams) int); ok { + r1 = rf(appCtx, officeUserID, role, params) + } else { + r1 = ret.Get(1).(int) + } + + if rf, ok := ret.Get(2).(func(appcontext.AppContext, uuid.UUID, roles.RoleType, *services.ListOrderParams) error); ok { + r2 = rf(appCtx, officeUserID, role, params) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + // ListOrders provides a mock function with given fields: appCtx, officeUserID, role, params func (_m *OrderFetcher) ListOrders(appCtx appcontext.AppContext, officeUserID uuid.UUID, role roles.RoleType, params *services.ListOrderParams) ([]models.Move, int, error) { ret := _m.Called(appCtx, officeUserID, role, params) diff --git a/pkg/services/mocks/WeightAllotmentFetcher.go b/pkg/services/mocks/WeightAllotmentFetcher.go new file mode 100644 index 00000000000..fa36bfbee2e --- /dev/null +++ b/pkg/services/mocks/WeightAllotmentFetcher.go @@ -0,0 +1,117 @@ +// Code generated by mockery. DO NOT EDIT. + +package mocks + +import ( + appcontext "github.com/transcom/mymove/pkg/appcontext" + internalmessages "github.com/transcom/mymove/pkg/gen/internalmessages" + + mock "github.com/stretchr/testify/mock" + + models "github.com/transcom/mymove/pkg/models" +) + +// WeightAllotmentFetcher is an autogenerated mock type for the WeightAllotmentFetcher type +type WeightAllotmentFetcher struct { + mock.Mock +} + +// GetAllWeightAllotments provides a mock function with given fields: appCtx +func (_m *WeightAllotmentFetcher) GetAllWeightAllotments(appCtx appcontext.AppContext) (map[internalmessages.OrderPayGrade]models.WeightAllotment, error) { + ret := _m.Called(appCtx) + + if len(ret) == 0 { + panic("no return value specified for GetAllWeightAllotments") + } + + var r0 map[internalmessages.OrderPayGrade]models.WeightAllotment + var r1 error + if rf, ok := ret.Get(0).(func(appcontext.AppContext) (map[internalmessages.OrderPayGrade]models.WeightAllotment, error)); ok { + return rf(appCtx) + } + if rf, ok := ret.Get(0).(func(appcontext.AppContext) map[internalmessages.OrderPayGrade]models.WeightAllotment); ok { + r0 = rf(appCtx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(map[internalmessages.OrderPayGrade]models.WeightAllotment) + } + } + + if rf, ok := ret.Get(1).(func(appcontext.AppContext) error); ok { + r1 = rf(appCtx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetWeightAllotment provides a mock function with given fields: appCtx, grade, ordersType +func (_m *WeightAllotmentFetcher) GetWeightAllotment(appCtx appcontext.AppContext, grade string, ordersType internalmessages.OrdersType) (models.WeightAllotment, error) { + ret := _m.Called(appCtx, grade, ordersType) + + if len(ret) == 0 { + panic("no return value specified for GetWeightAllotment") + } + + var r0 models.WeightAllotment + var r1 error + if rf, ok := ret.Get(0).(func(appcontext.AppContext, string, internalmessages.OrdersType) (models.WeightAllotment, error)); ok { + return rf(appCtx, grade, ordersType) + } + if rf, ok := ret.Get(0).(func(appcontext.AppContext, string, internalmessages.OrdersType) models.WeightAllotment); ok { + r0 = rf(appCtx, grade, ordersType) + } else { + r0 = ret.Get(0).(models.WeightAllotment) + } + + if rf, ok := ret.Get(1).(func(appcontext.AppContext, string, internalmessages.OrdersType) error); ok { + r1 = rf(appCtx, grade, ordersType) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetWeightAllotmentByOrdersType provides a mock function with given fields: appCtx, ordersType +func (_m *WeightAllotmentFetcher) GetWeightAllotmentByOrdersType(appCtx appcontext.AppContext, ordersType internalmessages.OrdersType) (models.WeightAllotment, error) { + ret := _m.Called(appCtx, ordersType) + + if len(ret) == 0 { + panic("no return value specified for GetWeightAllotmentByOrdersType") + } + + var r0 models.WeightAllotment + var r1 error + if rf, ok := ret.Get(0).(func(appcontext.AppContext, internalmessages.OrdersType) (models.WeightAllotment, error)); ok { + return rf(appCtx, ordersType) + } + if rf, ok := ret.Get(0).(func(appcontext.AppContext, internalmessages.OrdersType) models.WeightAllotment); ok { + r0 = rf(appCtx, ordersType) + } else { + r0 = ret.Get(0).(models.WeightAllotment) + } + + if rf, ok := ret.Get(1).(func(appcontext.AppContext, internalmessages.OrdersType) error); ok { + r1 = rf(appCtx, ordersType) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NewWeightAllotmentFetcher creates a new instance of WeightAllotmentFetcher. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewWeightAllotmentFetcher(t interface { + mock.TestingT + Cleanup(func()) +}) *WeightAllotmentFetcher { + mock := &WeightAllotmentFetcher{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/services/mocks/WeightRestrictor.go b/pkg/services/mocks/WeightRestrictor.go new file mode 100644 index 00000000000..6f7ad72bae4 --- /dev/null +++ b/pkg/services/mocks/WeightRestrictor.go @@ -0,0 +1,89 @@ +// Code generated by mockery. DO NOT EDIT. + +package mocks + +import ( + mock "github.com/stretchr/testify/mock" + appcontext "github.com/transcom/mymove/pkg/appcontext" + + models "github.com/transcom/mymove/pkg/models" +) + +// WeightRestrictor is an autogenerated mock type for the WeightRestrictor type +type WeightRestrictor struct { + mock.Mock +} + +// ApplyWeightRestrictionToEntitlement provides a mock function with given fields: appCtx, entitlement, weightRestriction, eTag +func (_m *WeightRestrictor) ApplyWeightRestrictionToEntitlement(appCtx appcontext.AppContext, entitlement models.Entitlement, weightRestriction int, eTag string) (*models.Entitlement, error) { + ret := _m.Called(appCtx, entitlement, weightRestriction, eTag) + + if len(ret) == 0 { + panic("no return value specified for ApplyWeightRestrictionToEntitlement") + } + + var r0 *models.Entitlement + var r1 error + if rf, ok := ret.Get(0).(func(appcontext.AppContext, models.Entitlement, int, string) (*models.Entitlement, error)); ok { + return rf(appCtx, entitlement, weightRestriction, eTag) + } + if rf, ok := ret.Get(0).(func(appcontext.AppContext, models.Entitlement, int, string) *models.Entitlement); ok { + r0 = rf(appCtx, entitlement, weightRestriction, eTag) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*models.Entitlement) + } + } + + if rf, ok := ret.Get(1).(func(appcontext.AppContext, models.Entitlement, int, string) error); ok { + r1 = rf(appCtx, entitlement, weightRestriction, eTag) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// RemoveWeightRestrictionFromEntitlement provides a mock function with given fields: appCtx, entitlement, eTag +func (_m *WeightRestrictor) RemoveWeightRestrictionFromEntitlement(appCtx appcontext.AppContext, entitlement models.Entitlement, eTag string) (*models.Entitlement, error) { + ret := _m.Called(appCtx, entitlement, eTag) + + if len(ret) == 0 { + panic("no return value specified for RemoveWeightRestrictionFromEntitlement") + } + + var r0 *models.Entitlement + var r1 error + if rf, ok := ret.Get(0).(func(appcontext.AppContext, models.Entitlement, string) (*models.Entitlement, error)); ok { + return rf(appCtx, entitlement, eTag) + } + if rf, ok := ret.Get(0).(func(appcontext.AppContext, models.Entitlement, string) *models.Entitlement); ok { + r0 = rf(appCtx, entitlement, eTag) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*models.Entitlement) + } + } + + if rf, ok := ret.Get(1).(func(appcontext.AppContext, models.Entitlement, string) error); ok { + r1 = rf(appCtx, entitlement, eTag) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NewWeightRestrictor creates a new instance of WeightRestrictor. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewWeightRestrictor(t interface { + mock.TestingT + Cleanup(func()) +}) *WeightRestrictor { + mock := &WeightRestrictor{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/services/move_task_order/move_task_order_fetcher.go b/pkg/services/move_task_order/move_task_order_fetcher.go index a0dee9339f1..50fc813bd06 100644 --- a/pkg/services/move_task_order/move_task_order_fetcher.go +++ b/pkg/services/move_task_order/move_task_order_fetcher.go @@ -351,13 +351,23 @@ func (f moveTaskOrderFetcher) FetchMoveTaskOrder(appCtx appcontext.AppContext, s mto.MTOServiceItems = loadedServiceItems if mto.Orders.DestinationGBLOC == nil { - newDutyLocationGBLOC, err := models.FetchGBLOCForPostalCode(appCtx.DB(), mto.Orders.NewDutyLocation.Address.PostalCode) - if err != nil { - err = apperror.NewBadDataError("New duty location GBLOC cannot be verified") - appCtx.Logger().Error(err.Error()) - return &models.Move{}, apperror.NewQueryError("DestinationGBLOC", err, "") + var newDutyLocationGBLOC *string + if *mto.Orders.NewDutyLocation.Address.IsOconus { + newDutyLocationGBLOCOconus, err := models.FetchAddressGbloc(appCtx.DB(), mto.Orders.NewDutyLocation.Address, mto.Orders.ServiceMember) + if err != nil { + return nil, apperror.NewNotFoundError(mto.Orders.NewDutyLocation.ID, "while looking for Duty Location Oconus GBLOC") + } + newDutyLocationGBLOC = newDutyLocationGBLOCOconus + } else { + newDutyLocationGBLOCConus, err := models.FetchGBLOCForPostalCode(appCtx.DB(), mto.Orders.NewDutyLocation.Address.PostalCode) + if err != nil { + err = apperror.NewBadDataError("New duty location GBLOC cannot be verified") + appCtx.Logger().Error(err.Error()) + return &models.Move{}, apperror.NewQueryError("DestinationGBLOC", err, "") + } + newDutyLocationGBLOC = &newDutyLocationGBLOCConus.GBLOC } - mto.Orders.DestinationGBLOC = &newDutyLocationGBLOC.GBLOC + mto.Orders.DestinationGBLOC = newDutyLocationGBLOC } return mto, nil diff --git a/pkg/services/order.go b/pkg/services/order.go index c1bd25d1b84..217f3e069f2 100644 --- a/pkg/services/order.go +++ b/pkg/services/order.go @@ -20,6 +20,7 @@ import ( type OrderFetcher interface { FetchOrder(appCtx appcontext.AppContext, orderID uuid.UUID) (*models.Order, error) ListOrders(appCtx appcontext.AppContext, officeUserID uuid.UUID, role roles.RoleType, params *ListOrderParams) ([]models.Move, int, error) + ListDestinationRequestsOrders(appCtx appcontext.AppContext, officeUserID uuid.UUID, role roles.RoleType, params *ListOrderParams) ([]models.Move, int, error) ListAllOrderLocations(appCtx appcontext.AppContext, officeUserID uuid.UUID, params *ListOrderParams) ([]models.Move, error) } diff --git a/pkg/services/order/order_fetcher.go b/pkg/services/order/order_fetcher.go index 923a4dfe82b..500cdbad41f 100644 --- a/pkg/services/order/order_fetcher.go +++ b/pkg/services/order/order_fetcher.go @@ -2,6 +2,7 @@ package order import ( "database/sql" + "encoding/json" "fmt" "regexp" "strings" @@ -9,6 +10,8 @@ import ( "github.com/gobuffalo/pop/v6" "github.com/gofrs/uuid" + "github.com/jinzhu/copier" + "github.com/lib/pq" "go.uber.org/zap" "github.com/transcom/mymove/pkg/appcontext" @@ -307,7 +310,118 @@ func (f orderFetcher) ListOrders(appCtx appcontext.AppContext, officeUserID uuid return moves, count, nil } -// TODO: Update query to select distinct duty locations +// this is a custom/temporary struct used in the below service object to get destination queue moves +type MoveWithCount struct { + models.Move + OrdersRaw json.RawMessage `json:"orders" db:"orders"` + Orders *models.Order `json:"-"` + MTOShipmentsRaw json.RawMessage `json:"mto_shipments" db:"mto_shipments"` + MTOShipments *models.MTOShipments `json:"-"` + CounselingOfficeRaw json.RawMessage `json:"counseling_transportation_office" db:"counseling_transportation_office"` + CounselingOffice *models.TransportationOffice `json:"-"` + TOOAssignedRaw json.RawMessage `json:"too_assigned" db:"too_assigned"` + TOOAssignedUser *models.OfficeUser `json:"-"` + TotalCount int64 `json:"total_count" db:"total_count"` +} + +type JSONB []byte + +func (j *JSONB) UnmarshalJSON(data []byte) error { + *j = data + return nil +} + +func (f orderFetcher) ListDestinationRequestsOrders(appCtx appcontext.AppContext, officeUserID uuid.UUID, role roles.RoleType, params *services.ListOrderParams) ([]models.Move, int, error) { + var moves []models.Move + var movesWithCount []MoveWithCount + + // getting the office user's GBLOC + gblocFetcher := officeuser.NewOfficeUserGblocFetcher() + officeUserGbloc, gblocErr := gblocFetcher.FetchGblocForOfficeUser(appCtx, officeUserID) + if gblocErr != nil { + return []models.Move{}, 0, gblocErr + } + + // calling the database function with all passed in parameters + err := appCtx.DB().RawQuery("SELECT * FROM get_destination_queue($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)", + officeUserGbloc, + params.CustomerName, + params.Edipi, + params.Emplid, + pq.Array(params.Status), + params.Locator, + params.RequestedMoveDate, + params.AppearedInTOOAt, + params.Branch, + strings.Join(params.OriginDutyLocation, " "), + params.CounselingOffice, + params.TOOAssignedUser, + params.Page, + params.PerPage, + params.Sort, + params.Order). + All(&movesWithCount) + + if err != nil { + return []models.Move{}, 0, err + } + + // each row is sent back with the total count from the db func, so we will take the value from the first one + var count int64 + if len(movesWithCount) > 0 { + count = movesWithCount[0].TotalCount + } else { + count = 0 + } + + // we have to manually loop through each move and populate the nested objects that the queue uses/needs + for i := range movesWithCount { + // populating Move.Orders struct + var order models.Order + if err := json.Unmarshal(movesWithCount[i].OrdersRaw, &order); err != nil { + return nil, 0, fmt.Errorf("error unmarshaling orders JSON: %w", err) + } + movesWithCount[i].OrdersRaw = nil + movesWithCount[i].Orders = &order + + // populating Move.MTOShipments array + var shipments models.MTOShipments + if err := json.Unmarshal(movesWithCount[i].MTOShipmentsRaw, &shipments); err != nil { + return nil, 0, fmt.Errorf("error unmarshaling shipments JSON: %w", err) + } + movesWithCount[i].MTOShipmentsRaw = nil + movesWithCount[i].MTOShipments = &shipments + + // populating Moves.CounselingOffice struct + var counselingTransportationOffice models.TransportationOffice + if err := json.Unmarshal(movesWithCount[i].CounselingOfficeRaw, &counselingTransportationOffice); err != nil { + return nil, 0, fmt.Errorf("error unmarshaling counseling_transportation_office JSON: %w", err) + } + movesWithCount[i].CounselingOfficeRaw = nil + movesWithCount[i].CounselingOffice = &counselingTransportationOffice + + // populating Moves.TOOAssigned struct + var tooAssigned models.OfficeUser + if err := json.Unmarshal(movesWithCount[i].TOOAssignedRaw, &tooAssigned); err != nil { + return nil, 0, fmt.Errorf("error unmarshaling too_assigned JSON: %w", err) + } + movesWithCount[i].TOOAssignedRaw = nil + movesWithCount[i].TOOAssignedUser = &tooAssigned + } + + // the handler consumes a Move object and NOT the MoveWithCount struct used in this func + // so we have to copy our custom struct into the Move struct + for _, moveWithCount := range movesWithCount { + var move models.Move + if err := copier.Copy(&move, &moveWithCount); err != nil { + return nil, 0, fmt.Errorf("error copying movesWithCount into Moves struct: %w", err) + } + moves = append(moves, move) + } + + return moves, int(count), nil +} + func (f orderFetcher) ListAllOrderLocations(appCtx appcontext.AppContext, officeUserID uuid.UUID, params *services.ListOrderParams) ([]models.Move, error) { var moves []models.Move var err error diff --git a/pkg/services/order/order_fetcher_test.go b/pkg/services/order/order_fetcher_test.go index 57e85401246..f597146e48e 100644 --- a/pkg/services/order/order_fetcher_test.go +++ b/pkg/services/order/order_fetcher_test.go @@ -5,6 +5,7 @@ import ( "time" "github.com/gofrs/uuid" + "github.com/stretchr/testify/mock" "github.com/transcom/mymove/pkg/auth" "github.com/transcom/mymove/pkg/factory" @@ -12,6 +13,7 @@ import ( "github.com/transcom/mymove/pkg/models/roles" "github.com/transcom/mymove/pkg/services" "github.com/transcom/mymove/pkg/services/entitlements" + "github.com/transcom/mymove/pkg/services/mocks" moveservice "github.com/transcom/mymove/pkg/services/move" officeuserservice "github.com/transcom/mymove/pkg/services/office_user" "github.com/transcom/mymove/pkg/testdatagen" @@ -2307,3 +2309,471 @@ func (suite *OrderServiceSuite) TestOriginDutyLocationFilter() { suite.Equal(locationName, string(expectedMoves[0].Orders.OriginDutyLocation.Name)) }) } + +func (suite *OrderServiceSuite) TestListDestinationRequestsOrders() { + army := models.AffiliationARMY + airForce := models.AffiliationAIRFORCE + spaceForce := models.AffiliationSPACEFORCE + usmc := models.AffiliationMARINES + + setupTestData := func(officeUserGBLOC string) (models.OfficeUser, auth.Session) { + + officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), []factory.Customization{ + { + Model: models.TransportationOffice{ + Gbloc: officeUserGBLOC, + }, + }, + }, []roles.RoleType{roles.RoleTypeTOO}) + + factory.FetchOrBuildPostalCodeToGBLOC(suite.DB(), "99501", officeUser.TransportationOffice.Gbloc) + + fetcher := &mocks.OfficeUserGblocFetcher{} + fetcher.On("FetchGblocForOfficeUser", + mock.AnythingOfType("*appcontext.appContext"), + officeUser.ID, + ).Return(officeUserGBLOC, nil) + + session := auth.Session{ + ApplicationName: auth.OfficeApp, + Roles: officeUser.User.Roles, + OfficeUserID: officeUser.ID, + IDToken: "fake_token", + AccessToken: "fakeAccessToken", + } + + return officeUser, session + } + + buildMoveKKFA := func() (models.Move, models.MTOShipment) { + postalCode := "90210" + factory.FetchOrBuildPostalCodeToGBLOC(suite.DB(), "90210", "KKFA") + + // setting up two moves, each with requested destination SIT service items + destinationAddress := factory.BuildAddress(suite.DB(), []factory.Customization{ + { + Model: models.Address{PostalCode: postalCode}, + }, + }, nil) + + move := factory.BuildAvailableToPrimeMove(suite.DB(), []factory.Customization{ + { + Model: models.Move{ + Status: models.MoveStatusAPPROVALSREQUESTED, + Show: models.BoolPointer(true), + }, + }}, nil) + + shipment := factory.BuildMTOShipment(suite.DB(), []factory.Customization{ + { + Model: models.MTOShipment{ + Status: models.MTOShipmentStatusApproved, + }, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: destinationAddress, + LinkOnly: true, + }, + }, nil) + + return move, shipment + } + + buildMoveZone2AK := func(branch models.ServiceMemberAffiliation) (models.Move, models.MTOShipment) { + // Create a USAF move in Alaska Zone II + // this is a hard coded uuid that is a us_post_region_cities_id within AK Zone II + zone2UUID, err := uuid.FromString("66768964-e0de-41f3-b9be-7ef32e4ae2b4") + suite.FatalNoError(err) + destinationAddress := factory.BuildAddress(suite.DB(), []factory.Customization{ + { + Model: models.Address{ + City: "Anchorage", + State: "AK", + PostalCode: "99501", + UsPostRegionCityID: &zone2UUID, + }, + }, + }, nil) + + // setting up two moves, each with requested destination SIT service items + move := factory.BuildAvailableToPrimeMove(suite.DB(), []factory.Customization{ + { + Model: models.Move{ + Status: models.MoveStatusAPPROVALSREQUESTED, + Show: models.BoolPointer(true), + }, + }, + { + Model: models.ServiceMember{ + Affiliation: &branch, + }, + }, + }, nil) + + shipment := factory.BuildMTOShipment(suite.DB(), []factory.Customization{ + { + Model: models.MTOShipment{ + Status: models.MTOShipmentStatusApproved, + }, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: destinationAddress, + LinkOnly: true, + }, + }, nil) + + return move, shipment + } + + buildMoveZone4AK := func(branch models.ServiceMemberAffiliation) (models.Move, models.MTOShipment) { + // Create a USAF move in Alaska Zone II + // this is a hard coded uuid that is a us_post_region_cities_id within AK Zone II + zone4UUID, err := uuid.FromString("78a6f230-9a3a-46ed-aa48-2e3decfe70ff") + suite.FatalNoError(err) + destinationAddress := factory.BuildAddress(suite.DB(), []factory.Customization{ + { + Model: models.Address{ + City: "Anchorage", + State: "AK", + PostalCode: "99501", + UsPostRegionCityID: &zone4UUID, + }, + }, + }, nil) + // setting up two moves, each with requested destination SIT service items + move := factory.BuildAvailableToPrimeMove(suite.DB(), []factory.Customization{ + { + Model: models.Move{ + Status: models.MoveStatusAPPROVALSREQUESTED, + Show: models.BoolPointer(true), + }, + }, + { + Model: models.ServiceMember{ + Affiliation: &branch, + }, + }, + }, nil) + + shipment := factory.BuildMTOShipment(suite.DB(), []factory.Customization{ + { + Model: models.MTOShipment{ + Status: models.MTOShipmentStatusApproved, + }, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: destinationAddress, + LinkOnly: true, + }, + }, nil) + + return move, shipment + } + + waf := entitlements.NewWeightAllotmentFetcher() + orderFetcher := NewOrderFetcher(waf) + + suite.Run("returns moves for KKFA GBLOC when destination address is in KKFA GBLOC", func() { + officeUser, session := setupTestData("KKFA") + // setting up two moves, each with requested destination SIT service items + move, shipment := buildMoveKKFA() + + // destination service item in SUBMITTED status + factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeDDFSIT, + }, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusSubmitted, + }, + }, + }, nil) + + move2, shipment2 := buildMoveKKFA() + + // destination shuttle + factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeDDSHUT, + }, + }, + { + Model: move2, + LinkOnly: true, + }, + { + Model: shipment2, + LinkOnly: true, + }, + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusSubmitted, + }, + }, + }, nil) + + move3, shipment3 := buildMoveKKFA() + factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeMS, + }, + }, + { + Model: move3, + LinkOnly: true, + }, + { + Model: shipment3, + LinkOnly: true, + }, + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusApproved, + }, + }, + }, nil) + factory.BuildShipmentAddressUpdate(suite.DB(), []factory.Customization{ + { + Model: shipment3, + LinkOnly: true, + }, + { + Model: move3, + LinkOnly: true, + }, + }, []factory.Trait{factory.GetTraitShipmentAddressUpdateRequested}) + + moves, moveCount, err := orderFetcher.ListDestinationRequestsOrders( + suite.AppContextWithSessionForTest(&session), officeUser.ID, roles.RoleTypeTOO, &services.ListOrderParams{}, + ) + + suite.FatalNoError(err) + suite.Equal(3, moveCount) + suite.Len(moves, 3) + }) + + suite.Run("returns moves for MBFL GBLOC including USAF/SF in Alaska Zone II", func() { + officeUser, session := setupTestData("MBFL") + + // setting up two moves, each with requested destination SIT service items + // a move associated with an air force customer containing AK Zone II shipment + move, shipment := buildMoveZone2AK(airForce) + + // destination service item in SUBMITTED status + factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeDDFSIT, + }, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusSubmitted, + }, + }, + }, nil) + + // Create a move outside Alaska Zone II (Zone IV in this case) + move2, shipment2 := buildMoveZone4AK(spaceForce) + + // destination service item in SUBMITTED status + factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeDDFSIT, + }, + }, + { + Model: move2, + LinkOnly: true, + }, + { + Model: shipment2, + LinkOnly: true, + }, + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusSubmitted, + }, + }, + }, nil) + + params := services.ListOrderParams{Status: []string{string(models.MoveStatusAPPROVALSREQUESTED)}} + moves, moveCount, err := orderFetcher.ListDestinationRequestsOrders( + suite.AppContextWithSessionForTest(&session), officeUser.ID, roles.RoleTypeTOO, ¶ms, + ) + + // we should get both moves back because one is in Zone II & the other is within the postal code GBLOC + suite.FatalNoError(err) + suite.Equal(2, moveCount) + suite.Len(moves, 2) + }) + + suite.Run("returns moves for JEAT GBLOC excluding USAF/SF in Alaska Zone II", func() { + officeUser, session := setupTestData("JEAT") + + // Create a move in Zone II, but not an air force or space force service member + move, shipment := buildMoveZone4AK(army) + + // destination service item in SUBMITTED status + factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeDDFSIT, + }, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusSubmitted, + }, + }, + }, nil) + + moves, moveCount, err := orderFetcher.ListDestinationRequestsOrders( + suite.AppContextWithSessionForTest(&session), officeUser.ID, roles.RoleTypeTOO, &services.ListOrderParams{}, + ) + + suite.FatalNoError(err) + suite.Equal(1, moveCount) + suite.Len(moves, 1) + }) + + suite.Run("returns moves for USMC GBLOC when moves belong to USMC servicemembers", func() { + officeUser, session := setupTestData("USMC") + + // setting up two moves, each with requested destination SIT service items + // both will be USMC moves, one in Zone II AK and the other not + move, shipment := buildMoveZone2AK(usmc) + + // destination service item in SUBMITTED status + factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeDDFSIT, + }, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusSubmitted, + }, + }, + }, nil) + + // this one won't be in Zone II + move2, shipment2 := buildMoveZone4AK(usmc) + + // destination shuttle + factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeDDSHUT, + }, + }, + { + Model: move2, + LinkOnly: true, + }, + { + Model: shipment2, + LinkOnly: true, + }, + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusSubmitted, + }, + }, + }, nil) + + move3, shipment3 := buildMoveZone4AK(usmc) + // we need to create a service item and attach it to the move/shipment + // else the query will exclude the move since it doesn't use LEFT JOINs + factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeMS, + }, + }, + { + Model: move3, + LinkOnly: true, + }, + { + Model: shipment3, + LinkOnly: true, + }, + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusApproved, + }, + }, + }, nil) + factory.BuildShipmentAddressUpdate(suite.DB(), []factory.Customization{ + { + Model: shipment3, + LinkOnly: true, + }, + { + Model: move3, + LinkOnly: true, + }, + }, []factory.Trait{factory.GetTraitShipmentAddressUpdateRequested}) + + moves, moveCount, err := orderFetcher.ListDestinationRequestsOrders( + suite.AppContextWithSessionForTest(&session), officeUser.ID, roles.RoleTypeTOO, &services.ListOrderParams{}, + ) + + // we should get three moves back since they're USMC moves and zone doesn't matter + suite.FatalNoError(err) + suite.Equal(3, moveCount) + suite.Len(moves, 3) + }) +} diff --git a/pkg/services/order/order_updater.go b/pkg/services/order/order_updater.go index 12821783d7a..e08896380c3 100644 --- a/pkg/services/order/order_updater.go +++ b/pkg/services/order/order_updater.go @@ -730,16 +730,27 @@ func updateOrderInTx(appCtx appcontext.AppContext, order models.Order, checks .. order.OriginDutyLocationID = &originDutyLocation.ID order.OriginDutyLocation = &originDutyLocation - dutyLocationGBLOC, err2 := models.FetchGBLOCForPostalCode(appCtx.DB(), originDutyLocation.Address.PostalCode) - if err2 != nil { - switch err2 { - case sql.ErrNoRows: - return nil, apperror.NewNotFoundError(originDutyLocation.ID, "while looking for Duty Location PostalCodeToGBLOC") - default: - return nil, apperror.NewQueryError("PostalCodeToGBLOC", err, "") + var originDutyLocationGBLOC *string + if *originDutyLocation.Address.IsOconus { + originDutyLocationGBLOCOconus, err := models.FetchAddressGbloc(appCtx.DB(), originDutyLocation.Address, order.ServiceMember) + if err != nil { + return nil, apperror.NewNotFoundError(originDutyLocation.ID, "while looking for Duty Location Oconus GBLOC") } + originDutyLocationGBLOC = originDutyLocationGBLOCOconus + } else { + originDutyLocationGBLOCConus, err2 := models.FetchGBLOCForPostalCode(appCtx.DB(), originDutyLocation.Address.PostalCode) + if err2 != nil { + switch err2 { + case sql.ErrNoRows: + return nil, apperror.NewNotFoundError(originDutyLocation.ID, "while looking for Duty Location PostalCodeToGBLOC") + default: + return nil, apperror.NewQueryError("PostalCodeToGBLOC", err, "") + } + } + originDutyLocationGBLOC = &originDutyLocationGBLOCConus.GBLOC } - order.OriginDutyLocationGBLOC = &dutyLocationGBLOC.GBLOC + + order.OriginDutyLocationGBLOC = originDutyLocationGBLOC } if order.Grade != nil || order.OriginDutyLocationID != nil { @@ -762,19 +773,29 @@ func updateOrderInTx(appCtx appcontext.AppContext, order models.Order, checks .. } } - newDestinationGBLOC, err := models.FetchGBLOCForPostalCode(appCtx.DB(), newDutyLocation.Address.PostalCode) - if err != nil { - switch err { - case sql.ErrNoRows: - return nil, apperror.NewNotFoundError(order.NewDutyLocationID, "while looking for DestinationGBLOC") - default: - return nil, apperror.NewQueryError("DestinationGBLOC", err, "") + var newDestinationGBLOC *string + if *newDutyLocation.Address.IsOconus { + newDestinationGBLOCOconus, err := models.FetchAddressGbloc(appCtx.DB(), newDutyLocation.Address, order.ServiceMember) + if err != nil { + return nil, apperror.NewNotFoundError(newDutyLocation.ID, "while looking for DestinationGBLOC Oconus") + } + newDestinationGBLOC = newDestinationGBLOCOconus + } else { + newDestinationGBLOCConus, err2 := models.FetchGBLOCForPostalCode(appCtx.DB(), newDutyLocation.Address.PostalCode) + if err2 != nil { + switch err { + case sql.ErrNoRows: + return nil, apperror.NewNotFoundError(order.NewDutyLocationID, "while looking for DestinationGBLOC") + default: + return nil, apperror.NewQueryError("DestinationGBLOC", err, "") + } } + newDestinationGBLOC = &newDestinationGBLOCConus.GBLOC } order.NewDutyLocationID = newDutyLocation.ID order.NewDutyLocation = newDutyLocation - order.DestinationGBLOC = &newDestinationGBLOC.GBLOC + order.DestinationGBLOC = newDestinationGBLOC } // Recalculate UB allowance of order entitlement diff --git a/pkg/services/support/move_task_order/move_task_order_creator.go b/pkg/services/support/move_task_order/move_task_order_creator.go index 85f3500c2de..d0bc162d54c 100644 --- a/pkg/services/support/move_task_order/move_task_order_creator.go +++ b/pkg/services/support/move_task_order/move_task_order_creator.go @@ -132,17 +132,27 @@ func createOrder(appCtx appcontext.AppContext, customer *models.ServiceMember, o order.OriginDutyLocation = originDutyLocation order.OriginDutyLocationID = &originDutyLocationID - var originDutyLocationGBLOC models.PostalCodeToGBLOC - originDutyLocationGBLOC, err = models.FetchGBLOCForPostalCode(appCtx.DB(), originDutyLocation.Address.PostalCode) - if err != nil { - switch err { - case sql.ErrNoRows: - return nil, apperror.NewNotFoundError(originDutyLocationID, "while looking for Duty Location PostalCodeToGBLOC") - default: - return nil, apperror.NewQueryError("PostalCodeToGBLOC", err, "") + var originDutyLocationGBLOC *string + if *originDutyLocation.Address.IsOconus { + originDutyLocationGBLOCOconus, err := models.FetchAddressGbloc(appCtx.DB(), originDutyLocation.Address, order.ServiceMember) + if err != nil { + return nil, apperror.NewNotFoundError(originDutyLocation.ID, "while looking for Duty Location Oconus GBLOC") + } + originDutyLocationGBLOC = originDutyLocationGBLOCOconus + } else { + originDutyLocationGBLOCConus, err := models.FetchGBLOCForPostalCode(appCtx.DB(), originDutyLocation.Address.PostalCode) + if err != nil { + switch err { + case sql.ErrNoRows: + return nil, apperror.NewNotFoundError(originDutyLocation.ID, "while looking for Duty Location PostalCodeToGBLOC") + default: + return nil, apperror.NewQueryError("PostalCodeToGBLOC", err, "") + } } + originDutyLocationGBLOC = &originDutyLocationGBLOCConus.GBLOC } - order.OriginDutyLocationGBLOC = &originDutyLocationGBLOC.GBLOC + + order.OriginDutyLocationGBLOC = originDutyLocationGBLOC } // Check that the uploaded orders document exists var uploadedOrders *models.Document diff --git a/pkg/services/transportation_office/transportation_office_fetcher_test.go b/pkg/services/transportation_office/transportation_office_fetcher_test.go index 9ce5bab765c..cd8345a8aa6 100644 --- a/pkg/services/transportation_office/transportation_office_fetcher_test.go +++ b/pkg/services/transportation_office/transportation_office_fetcher_test.go @@ -3,16 +3,15 @@ package transportationoffice import ( "fmt" "testing" - "time" "github.com/gofrs/uuid" "github.com/stretchr/testify/suite" - "github.com/transcom/mymove/pkg/appcontext" "github.com/transcom/mymove/pkg/auth" "github.com/transcom/mymove/pkg/factory" "github.com/transcom/mymove/pkg/models" "github.com/transcom/mymove/pkg/services" + "github.com/transcom/mymove/pkg/testdatagen" "github.com/transcom/mymove/pkg/testingsuite" ) @@ -190,19 +189,6 @@ func (suite *TransportationOfficeServiceSuite) Test_FindCounselingOffices() { } func (suite *TransportationOfficeServiceSuite) Test_Oconus_AK_FindCounselingOffices() { - testContractName := "Test_findOconusGblocDepartmentIndicator" - testContractCode := "Test_findOconusGblocDepartmentIndicator_Code" - testPostalCode := "99790" - testPostalCode2 := "99701" - testGbloc := "ABCD" - testGbloc2 := "EFGH" - testTransportationName := "TEST - PPO" - testTransportationName2 := "TEST - PPO2" - - serviceAffiliations := []models.ServiceMemberAffiliation{models.AffiliationARMY, - models.AffiliationNAVY, models.AffiliationMARINES, models.AffiliationAIRFORCE, models.AffiliationCOASTGUARD, - models.AffiliationSPACEFORCE} - setupServiceMember := func(serviceMemberAffiliation models.ServiceMemberAffiliation) models.ServiceMember { customServiceMember := models.ServiceMember{ FirstName: models.StringPointer("Gregory"), @@ -234,48 +220,19 @@ func (suite *TransportationOfficeServiceSuite) Test_Oconus_AK_FindCounselingOffi return serviceMember } - createContract := func(appCtx appcontext.AppContext, contractCode string, contractName string) (*models.ReContract, error) { - // See if contract code already exists. - exists, err := appCtx.DB().Where("code = ?", contractCode).Exists(&models.ReContract{}) - if err != nil { - return nil, fmt.Errorf("could not determine if contract code [%s] existed: %w", contractCode, err) - } - if exists { - return nil, fmt.Errorf("the provided contract code [%s] already exists", contractCode) - } + setupDataForOconusSearchCounselingOffice := func(postalCode string, gbloc string) (models.ReRateArea, models.OconusRateArea, models.UsPostRegionCity, models.DutyLocation) { + contract := testdatagen.FetchOrMakeReContract(suite.DB(), testdatagen.Assertions{}) - // Contract code is new; insert it. - contract := models.ReContract{ - Code: contractCode, - Name: contractName, - } - verrs, err := appCtx.DB().ValidateAndSave(&contract) - if verrs.HasAny() { - return nil, fmt.Errorf("validation errors when saving contract [%+v]: %w", contract, verrs) - } - if err != nil { - return nil, fmt.Errorf("could not save contract [%+v]: %w", contract, err) - } - return &contract, nil - } - - setupDataForOconusSearchCounselingOffice := func(contract models.ReContract, postalCode string, gbloc string, transportationName string) (models.ReRateArea, models.OconusRateArea, models.UsPostRegionCity, models.DutyLocation) { rateAreaCode := uuid.Must(uuid.NewV4()).String()[0:5] - rateArea := models.ReRateArea{ - ID: uuid.Must(uuid.NewV4()), - ContractID: contract.ID, - IsOconus: true, - Code: rateAreaCode, - Name: fmt.Sprintf("Alaska-%s", rateAreaCode), - Contract: contract, - } - verrs, err := suite.DB().ValidateAndCreate(&rateArea) - if verrs.HasAny() { - suite.Fail(verrs.Error()) - } - if err != nil { - suite.Fail(err.Error()) - } + rateArea := testdatagen.FetchOrMakeReRateArea(suite.DB(), testdatagen.Assertions{ + ReRateArea: models.ReRateArea{ + ContractID: contract.ID, + IsOconus: true, + Name: fmt.Sprintf("Alaska-%s", rateAreaCode), + Contract: contract, + }, + }) + suite.NotNil(rateArea) us_country, err := models.FetchCountryByCode(suite.DB(), "US") suite.NotNil(us_country) @@ -285,32 +242,18 @@ func (suite *TransportationOfficeServiceSuite) Test_Oconus_AK_FindCounselingOffi suite.NotNil(usprc) suite.FatalNoError(err) - oconusRateArea := models.OconusRateArea{ - ID: uuid.Must(uuid.NewV4()), - RateAreaId: rateArea.ID, - CountryId: us_country.ID, - UsPostRegionCityId: usprc.ID, - Active: true, - } - verrs, err = suite.DB().ValidateAndCreate(&oconusRateArea) - if verrs.HasAny() { - suite.Fail(verrs.Error()) - } - if err != nil { - suite.Fail(err.Error()) - } + oconusRateArea, err := models.FetchOconusRateAreaByCityId(suite.DB(), usprc.ID.String()) + suite.NotNil(oconusRateArea) + suite.Nil(err) - address := models.Address{ - StreetAddress1: "n/a", - City: "SomeCity", - State: "AK", - PostalCode: postalCode, - County: models.StringPointer("SomeCounty"), - IsOconus: models.BoolPointer(true), - UsPostRegionCityID: &usprc.ID, - CountryId: models.UUIDPointer(us_country.ID), - } - suite.MustSave(&address) + address := factory.BuildAddress(suite.DB(), []factory.Customization{ + { + Model: models.Address{ + IsOconus: models.BoolPointer(true), + UsPostRegionCityID: &usprc.ID, + }, + }, + }, nil) origDutyLocation := factory.BuildDutyLocation(suite.DB(), []factory.Customization{ { @@ -321,7 +264,7 @@ func (suite *TransportationOfficeServiceSuite) Test_Oconus_AK_FindCounselingOffi }, { Model: models.TransportationOffice{ - Name: transportationName, + Name: "TEST - PPO", Gbloc: gbloc, ProvidesCloseout: true, }, @@ -331,148 +274,68 @@ func (suite *TransportationOfficeServiceSuite) Test_Oconus_AK_FindCounselingOffi found_duty_location, _ := models.FetchDutyLocation(suite.DB(), origDutyLocation.ID) - return rateArea, oconusRateArea, *usprc, found_duty_location + return rateArea, *oconusRateArea, *usprc, found_duty_location } - suite.Run("success - findOconusGblocDepartmentIndicator - returns default GLOC for departmentAffiliation if no specific departmentAffilation mapping is defined", func() { - contract, err := createContract(suite.AppContextForTest(), testContractCode, testContractName) - suite.NotNil(contract) - suite.FatalNoError(err) - + suite.Run("success - findOconusGblocDepartmentIndicator - returns default GBLOC for departmentAffiliation if no specific departmentAffilation mapping is defined", func() { const fairbanksAlaskaPostalCode = "99790" - _, oconusRateArea, _, dutylocation := setupDataForOconusSearchCounselingOffice(*contract, fairbanksAlaskaPostalCode, testGbloc, testTransportationName) + _, oconusRateArea, _, dutylocation := setupDataForOconusSearchCounselingOffice(fairbanksAlaskaPostalCode, "JEAT") // setup department affiliation to GBLOC mappings - expected_gbloc := "TEST-GBLOC" - jppsoRegion := models.JppsoRegions{ - Code: expected_gbloc, - Name: "TEST PPM", - } - suite.MustSave(&jppsoRegion) - - gblocAors := models.GblocAors{ - JppsoRegionID: jppsoRegion.ID, - OconusRateAreaID: oconusRateArea.ID, - // DepartmentIndicator is nil, - } - suite.MustSave(&gblocAors) - - serviceAffiliations := []models.ServiceMemberAffiliation{models.AffiliationARMY, - models.AffiliationNAVY, models.AffiliationMARINES, models.AffiliationAIRFORCE, models.AffiliationCOASTGUARD, - models.AffiliationSPACEFORCE} - - // loop through and make sure all branches are using expected default GBLOC - for _, affiliation := range serviceAffiliations { - serviceMember := setupServiceMember(affiliation) - appCtx := suite.AppContextWithSessionForTest(&auth.Session{ - ServiceMemberID: serviceMember.ID, - }) - suite.Nil(err) - departmentIndictor, err := findOconusGblocDepartmentIndicator(appCtx, dutylocation) - suite.NotNil(departmentIndictor) - suite.Nil(err) - suite.Nil(departmentIndictor.DepartmentIndicator) - suite.Equal(expected_gbloc, departmentIndictor.Gbloc) - } - }) - - suite.Run("success - findOconusGblocDepartmentIndicator - returns specific GLOC for departmentAffiliation when a specific departmentAffilation mapping is defined", func() { - contract, err := createContract(suite.AppContextForTest(), testContractCode, testContractName) - suite.NotNil(contract) - suite.FatalNoError(err) + jppsoRegion, err := models.FetchJppsoRegionByCode(suite.DB(), "JEAT") + suite.NotNil(jppsoRegion) + suite.Nil(err) - _, oconusRateArea, _, dutylocation := setupDataForOconusSearchCounselingOffice(*contract, testPostalCode, testGbloc, testTransportationName) + gblocAors, err := models.FetchGblocAorsByJppsoCodeRateAreaDept(suite.DB(), jppsoRegion.ID, oconusRateArea.ID, models.DepartmentIndicatorARMY.String()) + suite.NotNil(gblocAors) + suite.Nil(err) - departmentIndicators := []models.DepartmentIndicator{models.DepartmentIndicatorARMY, - models.DepartmentIndicatorARMYCORPSOFENGINEERS, models.DepartmentIndicatorCOASTGUARD, - models.DepartmentIndicatorNAVYANDMARINES, models.DepartmentIndicatorAIRANDSPACEFORCE} + serviceMember := setupServiceMember(models.AffiliationARMY) + appCtx := suite.AppContextWithSessionForTest(&auth.Session{ + ServiceMemberID: serviceMember.ID, + }) + departmentIndictor, err := findOconusGblocDepartmentIndicator(appCtx, dutylocation) + suite.NotNil(departmentIndictor) + suite.Nil(err) + suite.Nil(departmentIndictor.DepartmentIndicator) + suite.Equal("JEAT", departmentIndictor.Gbloc) + }) - expectedAffiliationToDepartmentIndicatorMap := make(map[string]string, 0) - expectedAffiliationToDepartmentIndicatorMap[models.AffiliationARMY.String()] = models.DepartmentIndicatorARMY.String() - expectedAffiliationToDepartmentIndicatorMap[models.AffiliationNAVY.String()] = models.DepartmentIndicatorNAVYANDMARINES.String() - expectedAffiliationToDepartmentIndicatorMap[models.AffiliationMARINES.String()] = models.DepartmentIndicatorNAVYANDMARINES.String() - expectedAffiliationToDepartmentIndicatorMap[models.AffiliationAIRFORCE.String()] = models.DepartmentIndicatorAIRANDSPACEFORCE.String() - expectedAffiliationToDepartmentIndicatorMap[models.AffiliationCOASTGUARD.String()] = models.DepartmentIndicatorCOASTGUARD.String() - expectedAffiliationToDepartmentIndicatorMap[models.AffiliationSPACEFORCE.String()] = models.DepartmentIndicatorAIRANDSPACEFORCE.String() + suite.Run("success - findOconusGblocDepartmentIndicator - returns specific GBLOC for departmentAffiliation when a specific departmentAffilation mapping is defined -- simulate Zone 2 scenerio", func() { + const fairbanksAlaskaPostalCode = "99790" + _, oconusRateArea, _, dutylocation := setupDataForOconusSearchCounselingOffice(fairbanksAlaskaPostalCode, "MBFL") // setup department affiliation to GBLOC mappings - expected_gbloc := "TEST-GBLOC" - jppsoRegion := models.JppsoRegions{ - Code: expected_gbloc, - Name: "TEST PPM", - } - suite.MustSave(&jppsoRegion) + jppsoRegion, err := models.FetchJppsoRegionByCode(suite.DB(), "MBFL") + suite.NotNil(jppsoRegion) + suite.Nil(err) - defaultGblocAors := models.GblocAors{ - JppsoRegionID: jppsoRegion.ID, - OconusRateAreaID: oconusRateArea.ID, - //DepartmentIndicator is nil, - } - suite.MustSave(&defaultGblocAors) - - // setup specific departmentAffiliation mapping for each branch - for _, departmentIndicator := range departmentIndicators { - gblocAors := models.GblocAors{ - JppsoRegionID: jppsoRegion.ID, - OconusRateAreaID: oconusRateArea.ID, - DepartmentIndicator: models.StringPointer(departmentIndicator.String()), - } - suite.MustSave(&gblocAors) - } + gblocAors, err := models.FetchGblocAorsByJppsoCodeRateAreaDept(suite.DB(), jppsoRegion.ID, oconusRateArea.ID, models.DepartmentIndicatorAIRANDSPACEFORCE.String()) + suite.NotNil(gblocAors) + suite.Nil(err) // loop through and make sure all branches are using it's own dedicated GBLOC and not default - for _, affiliation := range serviceAffiliations { - serviceMember := setupServiceMember(affiliation) - appCtx := suite.AppContextWithSessionForTest(&auth.Session{ - ServiceMemberID: serviceMember.ID, - }) - suite.Nil(err) - departmentIndictor, err := findOconusGblocDepartmentIndicator(appCtx, dutylocation) - suite.NotNil(departmentIndictor) - suite.Nil(err) - suite.NotNil(departmentIndictor.DepartmentIndicator) - if match, ok := expectedAffiliationToDepartmentIndicatorMap[affiliation.String()]; ok { - // verify service member's affiliation matches on specific departmentIndicator mapping record - suite.Equal(match, *departmentIndictor.DepartmentIndicator) - } else { - suite.Fail(fmt.Sprintf("key does not exist for %s", affiliation.String())) - } - suite.Equal(expected_gbloc, departmentIndictor.Gbloc) - } - }) - - suite.Run("failure -- returns error when there are default and no department specific GBLOC", func() { - contract, err := createContract(suite.AppContextForTest(), testContractCode, testContractName) - suite.NotNil(contract) - suite.FatalNoError(err) - - _, _, _, dutylocation := setupDataForOconusSearchCounselingOffice(*contract, testPostalCode, testGbloc, testTransportationName) - - // No specific departmentAffiliation mapping or default were created. - // Expect an error response when nothing is found. serviceMember := setupServiceMember(models.AffiliationAIRFORCE) appCtx := suite.AppContextWithSessionForTest(&auth.Session{ ServiceMemberID: serviceMember.ID, }) suite.Nil(err) departmentIndictor, err := findOconusGblocDepartmentIndicator(appCtx, dutylocation) - suite.Nil(departmentIndictor) - suite.NotNil(err) + suite.NotNil(departmentIndictor) + suite.Nil(err) + suite.NotNil(departmentIndictor.DepartmentIndicator) + suite.Equal(models.DepartmentIndicatorAIRANDSPACEFORCE.String(), *departmentIndictor.DepartmentIndicator) + suite.Equal("MBFL", departmentIndictor.Gbloc) }) suite.Run("failure - findOconusGblocDepartmentIndicator - returns error when find service member ID fails", func() { - contract, err := createContract(suite.AppContextForTest(), testContractCode, testContractName) - suite.NotNil(contract) - suite.FatalNoError(err) - - _, _, _, dutylocation := setupDataForOconusSearchCounselingOffice(*contract, testPostalCode, testGbloc, testTransportationName) + _, _, _, dutylocation := setupDataForOconusSearchCounselingOffice("99714", "JEAT") appCtx := suite.AppContextWithSessionForTest(&auth.Session{ // create fake service member ID to raise NOT found error ServiceMemberID: uuid.Must(uuid.NewV4()), }) - suite.Nil(err) departmentIndictor, err := findOconusGblocDepartmentIndicator(appCtx, dutylocation) suite.Nil(departmentIndictor) suite.NotNil(err) @@ -489,33 +352,16 @@ func (suite *TransportationOfficeServiceSuite) Test_Oconus_AK_FindCounselingOffi }) suite.Run("success - offices using default departmentIndicator mapping", func() { - contract, err := createContract(suite.AppContextForTest(), testContractCode, testContractName) - suite.NotNil(contract) - suite.FatalNoError(err) - - _, oconusRateArea, _, dutylocation := setupDataForOconusSearchCounselingOffice(*contract, testPostalCode, testGbloc, testTransportationName) + _, oconusRateArea, _, dutylocation := setupDataForOconusSearchCounselingOffice("99619", "MAPS") // setup department affiliation to GBLOC mappings - jppsoRegion := models.JppsoRegions{ - Code: testGbloc, - Name: "TEST PPM", - } - suite.MustSave(&jppsoRegion) - - gblocAors := models.GblocAors{ - JppsoRegionID: jppsoRegion.ID, - OconusRateAreaID: oconusRateArea.ID, - // DepartmentIndicator is nil, - } - suite.MustSave(&gblocAors) + jppsoRegion, err := models.FetchJppsoRegionByCode(suite.DB(), "MAPS") + suite.NotNil(jppsoRegion) + suite.Nil(err) - postalCodeToGBLOC := models.PostalCodeToGBLOC{ - PostalCode: testPostalCode, - GBLOC: testGbloc, - CreatedAt: time.Now(), - UpdatedAt: time.Now(), - } - suite.MustSave(&postalCodeToGBLOC) + gblocAors, err := models.FetchGblocAorsByJppsoCodeRateAreaDept(suite.DB(), jppsoRegion.ID, oconusRateArea.ID, models.DepartmentIndicatorARMY.String()) + suite.NotNil(gblocAors) + suite.Nil(err) serviceMember := setupServiceMember(models.AffiliationAIRFORCE) appCtx := suite.AppContextWithSessionForTest(&auth.Session{ @@ -527,15 +373,15 @@ func (suite *TransportationOfficeServiceSuite) Test_Oconus_AK_FindCounselingOffi suite.NotNil(offices) suite.Nil(err) suite.Equal(1, len(offices)) - suite.Equal(testTransportationName, offices[0].Name) + suite.Equal("TEST - PPO", offices[0].Name) // add another transportation office factory.BuildTransportationOffice(suite.DB(), []factory.Customization{ { Model: models.TransportationOffice{ - Name: testTransportationName2, + Name: "TEST - PPO2", ProvidesCloseout: true, - Gbloc: testGbloc, + Gbloc: "MAPS", }, }, }, nil) @@ -545,100 +391,6 @@ func (suite *TransportationOfficeServiceSuite) Test_Oconus_AK_FindCounselingOffi suite.Equal(2, len(offices)) }) - suite.Run("success - returns correct office based on service affiliation -- simulate Zone 2 scenerio", func() { - contract, err := createContract(suite.AppContextForTest(), testContractCode, testContractName) - suite.NotNil(contract) - suite.FatalNoError(err) - - _, oconusRateArea, _, dutylocation := setupDataForOconusSearchCounselingOffice(*contract, testPostalCode, testGbloc, testTransportationName) - - // ****************************************************************************** - // setup department affiliation to GBLOC mappings for AF/SF - // ****************************************************************************** - jppsoRegion_AFSF := models.JppsoRegions{ - Code: testGbloc, - Name: "TEST PPO", - } - suite.MustSave(&jppsoRegion_AFSF) - - gblocAors_AFSF := models.GblocAors{ - JppsoRegionID: jppsoRegion_AFSF.ID, - OconusRateAreaID: oconusRateArea.ID, - DepartmentIndicator: models.StringPointer(models.DepartmentIndicatorAIRANDSPACEFORCE.String()), - } - suite.MustSave(&gblocAors_AFSF) - - postalCodeToGBLOC_AFSF := models.PostalCodeToGBLOC{ - PostalCode: testPostalCode, - GBLOC: testGbloc, - CreatedAt: time.Now(), - UpdatedAt: time.Now(), - } - suite.MustSave(&postalCodeToGBLOC_AFSF) - // ****************************************************************************** - - // ****************************************************************************** - // setup department affiliation to GBLOC mappings for other branches NOT AF/SF - // ****************************************************************************** - jppsoRegion_not_AFSF := models.JppsoRegions{ - Code: testGbloc2, - Name: "TEST PPO 2", - } - suite.MustSave(&jppsoRegion_not_AFSF) - - gblocAors_not_AFSF := models.GblocAors{ - JppsoRegionID: jppsoRegion_not_AFSF.ID, - OconusRateAreaID: oconusRateArea.ID, - } - suite.MustSave(&gblocAors_not_AFSF) - - postalCodeToGBLOC_not_AFSF := models.PostalCodeToGBLOC{ - PostalCode: testPostalCode2, - GBLOC: testGbloc2, - CreatedAt: time.Now(), - UpdatedAt: time.Now(), - } - suite.MustSave(&postalCodeToGBLOC_not_AFSF) - - // add transportation office for other branches not AF/SF - factory.BuildTransportationOffice(suite.DB(), []factory.Customization{ - { - Model: models.TransportationOffice{ - Name: testTransportationName2, - ProvidesCloseout: true, - Gbloc: testGbloc2, - }, - }, - }, nil) - // ****************************************************************************** - - for _, affiliation := range serviceAffiliations { - serviceMember := setupServiceMember(affiliation) - if affiliation == models.AffiliationAIRFORCE || affiliation == models.AffiliationSPACEFORCE { - appCtx := suite.AppContextWithSessionForTest(&auth.Session{ - ServiceMemberID: serviceMember.ID, - }) - offices, err := findCounselingOffice(appCtx, dutylocation.ID) - suite.NotNil(offices) - suite.Nil(err) - suite.Equal(1, len(offices)) - // verify expected office is for AF/SF and not for Navy ..etc.. - suite.Equal(testTransportationName, offices[0].Name) - suite.NotEqual(testTransportationName2, offices[0].Name) - } else { - appCtx := suite.AppContextWithSessionForTest(&auth.Session{ - ServiceMemberID: serviceMember.ID, - }) - offices, err := findCounselingOffice(appCtx, dutylocation.ID) - suite.NotNil(offices) - suite.Nil(err) - suite.Equal(1, len(offices)) - // verify expected office is for Navy ..etc.. and not AF/SF - suite.Equal(testTransportationName2, offices[0].Name) - suite.NotEqual(testTransportationName, offices[0].Name) - } - } - }) } func (suite *TransportationOfficeServiceSuite) Test_GetTransportationOffice() { diff --git a/scripts/db-truncate b/scripts/db-truncate index b53aa009a51..f1b0d6db10a 100755 --- a/scripts/db-truncate +++ b/scripts/db-truncate @@ -16,7 +16,8 @@ BEGIN 're_zip3s','zip3_distances', 're_contracts', 're_domestic_service_areas', 're_intl_prices', 're_intl_other_prices', 're_domestic_linehaul_prices', 're_domestic_service_area_prices', 're_domestic_other_prices', 'pay_grades', - 'hhg_allowances', 'roles')) LOOP + 'hhg_allowances', + 'jppso_regions', 'jppso_region_state_assignments', 'gbloc_aors', 'roles')) LOOP EXECUTE 'TRUNCATE TABLE ' || quote_ident(r.tablename) || ' CASCADE'; END LOOP; END \$\$; diff --git a/src/constants/routes.js b/src/constants/routes.js index 1c4121aef59..a018cef31ea 100644 --- a/src/constants/routes.js +++ b/src/constants/routes.js @@ -4,8 +4,8 @@ export const generalRoutes = { REQUEST_ACCOUNT: '/request-account', PRIVACY_SECURITY_POLICY_PATH: '/privacy-and-security-policy', ACCESSIBILITY_PATH: '/accessibility', - QUEUE_SEARCH_PATH: 'Search', - BASE_QUEUE_SEARCH_PATH: '/Search', + QUEUE_SEARCH_PATH: 'search', + BASE_QUEUE_SEARCH_PATH: '/search', }; export const customerRoutes = { @@ -120,6 +120,8 @@ export const tooRoutes = { BASE_SHIPMENT_EDIT_PATH: `${BASE_MOVES_PATH}/shipments/:shipmentId`, MOVE_QUEUE: `move-queue`, BASE_MOVE_QUEUE: `/move-queue`, + BASE_DESTINATION_REQUESTS_QUEUE: `/destination-requests`, + DESTINATION_REQUESTS_QUEUE: `destination-requests`, SHIPMENT_EDIT_PATH: 'shipments/:shipmentId', BASE_MOVE_VIEW_PATH: `${BASE_MOVES_PATH}/details`, MOVE_VIEW_PATH: 'details', diff --git a/src/hooks/queries.js b/src/hooks/queries.js index ce469702359..749f7602a91 100644 --- a/src/hooks/queries.js +++ b/src/hooks/queries.js @@ -34,6 +34,7 @@ import { getPPMActualWeight, searchCustomers, getGBLOCs, + getDestinationRequestsQueue, getBulkAssignmentData, } from 'services/ghcApi'; import { getLoggedInUserQueries } from 'services/internalApi'; @@ -586,6 +587,28 @@ export const useMovesQueueQueries = ({ }; }; +export const useDestinationRequestsQueueQueries = ({ + sort, + order, + filters = [], + currentPage = PAGINATION_PAGE_DEFAULT, + currentPageSize = PAGINATION_PAGE_SIZE_DEFAULT, + viewAsGBLOC, +}) => { + const { data = {}, ...movesQueueQuery } = useQuery( + [MOVES_QUEUE, { sort, order, filters, currentPage, currentPageSize, viewAsGBLOC }], + ({ queryKey }) => getDestinationRequestsQueue(...queryKey), + ); + const { isLoading, isError, isSuccess } = movesQueueQuery; + const { queueMoves, ...dataProps } = data; + return { + queueResult: { data: queueMoves, ...dataProps }, + isLoading, + isError, + isSuccess, + }; +}; + export const useServicesCounselingQueuePPMQueries = ({ sort, order, diff --git a/src/pages/Office/MoveQueue/MoveQueue.jsx b/src/pages/Office/MoveQueue/MoveQueue.jsx index 95b703189fc..36e090a48de 100644 --- a/src/pages/Office/MoveQueue/MoveQueue.jsx +++ b/src/pages/Office/MoveQueue/MoveQueue.jsx @@ -6,8 +6,13 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import styles from './MoveQueue.module.scss'; import { createHeader } from 'components/Table/utils'; -import { useMovesQueueQueries, useUserQueries, useMoveSearchQueries } from 'hooks/queries'; -import { getMovesQueue } from 'services/ghcApi'; +import { + useMovesQueueQueries, + useUserQueries, + useMoveSearchQueries, + useDestinationRequestsQueueQueries, +} from 'hooks/queries'; +import { getDestinationRequestsQueue, getMovesQueue } from 'services/ghcApi'; import { formatDateFromIso, serviceMemberAgencyLabel } from 'utils/formatters'; import MultiSelectCheckBoxFilter from 'components/Table/Filters/MultiSelectCheckBoxFilter'; import SelectFilter from 'components/Table/Filters/SelectFilter'; @@ -270,6 +275,15 @@ const MoveQueue = ({ isQueueManagementFFEnabled, userPrivileges, isBulkAssignmen Task Order Queue , + (isActive ? 'usa-current' : '')} + to={tooRoutes.BASE_DESTINATION_REQUESTS_QUEUE} + > + + Destination Requests Queue + + , (isActive ? 'usa-current' : '')} @@ -338,6 +352,32 @@ const MoveQueue = ({ isQueueManagementFFEnabled, userPrivileges, isBulkAssignmen ); } + if (queueType === tooRoutes.DESTINATION_REQUESTS_QUEUE) { + return ( +
+ {renderNavBar()} + +
+ ); + } return ; }; diff --git a/src/pages/Office/MoveQueue/MoveQueue.test.jsx b/src/pages/Office/MoveQueue/MoveQueue.test.jsx index 4e5ec01cd33..87defd030a8 100644 --- a/src/pages/Office/MoveQueue/MoveQueue.test.jsx +++ b/src/pages/Office/MoveQueue/MoveQueue.test.jsx @@ -328,7 +328,7 @@ describe('MoveQueue', () => { wrapper.update(); expect(wrapper.find('[data-testid="multi-value-container"]').text()).toEqual('New move'); }); - it('renders Search and Move Queue tabs', () => { + it('renders Search, Destination Queue and Move Queue tabs', () => { reactRouterDom.useParams.mockReturnValue({ queueType: generalRoutes.QUEUE_SEARCH_PATH }); render( @@ -338,6 +338,7 @@ describe('MoveQueue', () => { expect(screen.getByTestId('closeout-tab-link')).toBeInTheDocument(); expect(screen.getByTestId('search-tab-link')).toBeInTheDocument(); expect(screen.getByText('Task Order Queue', { selector: 'span' })).toBeInTheDocument(); + expect(screen.getByText('Destination Requests Queue', { selector: 'span' })).toBeInTheDocument(); expect(screen.getByText('Search', { selector: 'span' })).toBeInTheDocument(); }); it('renders TableQueue when Search tab is selected', () => { diff --git a/src/pages/Office/ServicesCounselingQueue/ServicesCounselingQueue.jsx b/src/pages/Office/ServicesCounselingQueue/ServicesCounselingQueue.jsx index 44b11a5567d..6518eda8080 100644 --- a/src/pages/Office/ServicesCounselingQueue/ServicesCounselingQueue.jsx +++ b/src/pages/Office/ServicesCounselingQueue/ServicesCounselingQueue.jsx @@ -609,7 +609,7 @@ const ServicesCounselingQueue = ({ return ; }; - if (queueType === 'Search') { + if (queueType === generalRoutes.QUEUE_SEARCH_PATH) { return (
{renderNavBar()} diff --git a/src/services/ghcApi.js b/src/services/ghcApi.js index 1b787b7b8ad..d405122099f 100644 --- a/src/services/ghcApi.js +++ b/src/services/ghcApi.js @@ -632,6 +632,22 @@ export async function getMovesQueue( ); } +export async function getDestinationRequestsQueue( + key, + { sort, order, filters = [], currentPage = 1, currentPageSize = 20, viewAsGBLOC }, +) { + const operationPath = 'queues.getDestinationRequestsQueue'; + const paramFilters = {}; + filters.forEach((filter) => { + paramFilters[`${filter.id}`] = filter.value; + }); + return makeGHCRequest( + operationPath, + { sort, order, page: currentPage, perPage: currentPageSize, viewAsGBLOC, ...paramFilters }, + { schemaKey: 'queueMovesResult', normalize: false }, + ); +} + export async function getServicesCounselingQueue( key, { sort, order, filters = [], currentPage = 1, currentPageSize = 20, needsPPMCloseout = false, viewAsGBLOC }, diff --git a/swagger-def/ghc.yaml b/swagger-def/ghc.yaml index 836dc696e8c..4437679cf39 100644 --- a/swagger-def/ghc.yaml +++ b/swagger-def/ghc.yaml @@ -3735,6 +3735,111 @@ paths: $ref: '#/responses/PermissionDenied' '500': $ref: '#/responses/ServerError' + /queues/destination-requests: + get: + produces: + - application/json + summary: Gets queued list of all customer moves by GBLOC that have both CONUS & OCONUS destination requests (destination SIT, destination shuttle, address requests) + description: > + A TOO will view this queue when they have destination requests tied to their GBLOC. This includes unapproved destination SIT service items, destination shuttle service items and destination address requests that are not yet approved by the TOO. + operationId: getDestinationRequestsQueue + tags: + - queues + parameters: + - in: query + name: page + type: integer + description: requested page of results + - in: query + name: perPage + type: integer + description: results per page + - in: query + name: sort + type: string + enum: + [ + customerName, + edipi, + emplid, + branch, + locator, + status, + originDutyLocation, + destinationDutyLocation, + requestedMoveDate, + appearedInTooAt, + assignedTo, + counselingOffice, + ] + description: field that results should be sorted by + - in: query + name: order + type: string + enum: [asc, desc] + description: direction of sort order if applied + - in: query + name: branch + type: string + - in: query + name: locator + type: string + - in: query + name: customerName + type: string + - in: query + name: edipi + type: string + - in: query + name: emplid + type: string + - in: query + name: originDutyLocation + type: array + uniqueItems: true + collectionFormat: multi + items: + type: string + - in: query + name: destinationDutyLocation + type: string + - in: query + name: appearedInTooAt + type: string + format: date-time + - in: query + name: requestedMoveDate + type: string + description: filters the requested pickup date of a shipment on the move + - in: query + name: status + type: array + description: Filtering for the status. + uniqueItems: true + items: + type: string + enum: + - SUBMITTED + - SERVICE COUNSELING COMPLETED + - APPROVALS REQUESTED + - in: query + name: assignedTo + type: string + description: | + Used to illustrate which user is assigned to this move. + - in: query + name: counselingOffice + type: string + description: filters using a counselingOffice name of the move + responses: + '200': + description: Successfully returned all moves matching the criteria + schema: + $ref: '#/definitions/QueueMovesResult' + '403': + $ref: '#/responses/PermissionDenied' + '500': + $ref: '#/responses/ServerError' /queues/payment-requests: get: produces: diff --git a/swagger/ghc.yaml b/swagger/ghc.yaml index 54131042af0..7b507636923 100644 --- a/swagger/ghc.yaml +++ b/swagger/ghc.yaml @@ -3901,6 +3901,117 @@ paths: $ref: '#/responses/PermissionDenied' '500': $ref: '#/responses/ServerError' + /queues/destination-requests: + get: + produces: + - application/json + summary: >- + Gets queued list of all customer moves by GBLOC that have both CONUS & + OCONUS destination requests (destination SIT, destination shuttle, + address requests) + description: > + A TOO will view this queue when they have destination requests tied to + their GBLOC. This includes unapproved destination SIT service items, + destination shuttle service items and destination address requests that + are not yet approved by the TOO. + operationId: getDestinationRequestsQueue + tags: + - queues + parameters: + - in: query + name: page + type: integer + description: requested page of results + - in: query + name: perPage + type: integer + description: results per page + - in: query + name: sort + type: string + enum: + - customerName + - edipi + - emplid + - branch + - locator + - status + - originDutyLocation + - destinationDutyLocation + - requestedMoveDate + - appearedInTooAt + - assignedTo + - counselingOffice + description: field that results should be sorted by + - in: query + name: order + type: string + enum: + - asc + - desc + description: direction of sort order if applied + - in: query + name: branch + type: string + - in: query + name: locator + type: string + - in: query + name: customerName + type: string + - in: query + name: edipi + type: string + - in: query + name: emplid + type: string + - in: query + name: originDutyLocation + type: array + uniqueItems: true + collectionFormat: multi + items: + type: string + - in: query + name: destinationDutyLocation + type: string + - in: query + name: appearedInTooAt + type: string + format: date-time + - in: query + name: requestedMoveDate + type: string + description: filters the requested pickup date of a shipment on the move + - in: query + name: status + type: array + description: Filtering for the status. + uniqueItems: true + items: + type: string + enum: + - SUBMITTED + - SERVICE COUNSELING COMPLETED + - APPROVALS REQUESTED + - in: query + name: assignedTo + type: string + description: | + Used to illustrate which user is assigned to this move. + - in: query + name: counselingOffice + type: string + description: filters using a counselingOffice name of the move + responses: + '200': + description: Successfully returned all moves matching the criteria + schema: + $ref: '#/definitions/QueueMovesResult' + '403': + $ref: '#/responses/PermissionDenied' + '500': + $ref: '#/responses/ServerError' /queues/payment-requests: get: produces: