freight_kit 0.1.20 → 0.1.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (466) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +0 -2
  3. data/README.md +6 -5
  4. data/Rakefile +4 -0
  5. data/VERSION +1 -1
  6. data/configuration/locations/amazon_warehouses.yml +3330 -0
  7. data/freight_kit-0.1.21.gem +0 -0
  8. data/freight_kit.gemspec +11 -22
  9. data/lib/freight_kit/address_normalizer.rb +24 -0
  10. data/lib/freight_kit/amazon_warehouse.rb +33 -0
  11. data/lib/freight_kit/api_clients/soap_client.rb +33 -10
  12. data/lib/freight_kit/carrier.rb +248 -302
  13. data/lib/freight_kit/carriers/a1_express.rb +25 -0
  14. data/lib/freight_kit/carriers/a_duie_pyle.rb +30 -0
  15. data/lib/freight_kit/carriers/aaa_cooper.rb +11 -0
  16. data/lib/freight_kit/carriers/aaa_expedited_services.rb +10 -0
  17. data/lib/freight_kit/carriers/ab_brothers_usa_inc.rb +12 -0
  18. data/lib/freight_kit/carriers/aberdeen_express_inc.rb +28 -0
  19. data/lib/freight_kit/carriers/abf_freight_system.rb +475 -0
  20. data/lib/freight_kit/carriers/access_transport.rb +10 -0
  21. data/lib/freight_kit/carriers/action_express.rb +10 -0
  22. data/lib/freight_kit/carriers/adams_and_companies.rb +10 -0
  23. data/lib/freight_kit/carriers/advance_distribution.rb +28 -0
  24. data/lib/freight_kit/carriers/alcon_transport.rb +10 -0
  25. data/lib/freight_kit/carriers/all_freight.rb +10 -0
  26. data/lib/freight_kit/carriers/alliance_transportation_group.rb +10 -0
  27. data/lib/freight_kit/carriers/allstate_transport.rb +10 -0
  28. data/lib/freight_kit/carriers/aloha_freight_forwarders.rb +31 -0
  29. data/lib/freight_kit/carriers/amado_trucking.rb +31 -0
  30. data/lib/freight_kit/carriers/american_fast_freight.rb +28 -0
  31. data/lib/freight_kit/carriers/amigos_service_transportation.rb +10 -0
  32. data/lib/freight_kit/carriers/anderson_towing_and_transport.rb +10 -0
  33. data/lib/freight_kit/carriers/apex_transporting.rb +10 -0
  34. data/lib/freight_kit/carriers/archer_cargo.rb +35 -0
  35. data/lib/freight_kit/carriers/armstrong_transport_group.rb +10 -0
  36. data/lib/freight_kit/carriers/autobahn_logistics.rb +10 -0
  37. data/lib/freight_kit/carriers/averitt_express.rb +30 -0
  38. data/lib/freight_kit/carriers/ba_transportation.rb +10 -0
  39. data/lib/freight_kit/carriers/balkin_express.rb +10 -0
  40. data/lib/freight_kit/carriers/bay_area_express.rb +10 -0
  41. data/lib/freight_kit/carriers/bc_freightways.rb +11 -0
  42. data/lib/freight_kit/carriers/benjamin_best_freight_inc.rb +37 -0
  43. data/lib/freight_kit/carriers/bennett_trucking.rb +10 -0
  44. data/lib/freight_kit/carriers/best_overnite_express.rb +78 -0
  45. data/lib/freight_kit/carriers/best_trucking.rb +10 -0
  46. data/lib/freight_kit/carriers/bestway_transport.rb +10 -0
  47. data/lib/freight_kit/carriers/bryan_systems.rb +10 -0
  48. data/lib/freight_kit/carriers/c_and_w_express.rb +10 -0
  49. data/lib/freight_kit/carriers/campbell_trucking.rb +10 -0
  50. data/lib/freight_kit/carriers/carde_transportation.rb +10 -0
  51. data/lib/freight_kit/carriers/cardinal_logistics.rb +28 -0
  52. data/lib/freight_kit/carriers/cdc_transport.rb +10 -0
  53. data/lib/freight_kit/carriers/cdo_express_diversified.rb +10 -0
  54. data/lib/freight_kit/carriers/cedar_supply_trucking.rb +10 -0
  55. data/lib/freight_kit/carriers/central_freight_lines.rb +12 -0
  56. data/lib/freight_kit/carriers/central_transport.rb +12 -0
  57. data/lib/freight_kit/carriers/chicago_suburban_express.rb +28 -0
  58. data/lib/freight_kit/carriers/city_logistics.rb +11 -0
  59. data/lib/freight_kit/carriers/clear_lane_freight_systems.rb +474 -0
  60. data/lib/freight_kit/carriers/cleopatra_trucking.rb +10 -0
  61. data/lib/freight_kit/carriers/clifford_transportation.rb +10 -0
  62. data/lib/freight_kit/carriers/cms_domestic.rb +25 -0
  63. data/lib/freight_kit/carriers/cnd_logistics.rb +10 -0
  64. data/lib/freight_kit/carriers/coast_to_coast_transport.rb +27 -0
  65. data/lib/freight_kit/carriers/countrywide_carriers.rb +10 -0
  66. data/lib/freight_kit/carriers/cpl_express.rb +31 -0
  67. data/lib/freight_kit/carriers/crosby_trucking_service.rb +29 -0
  68. data/lib/freight_kit/carriers/cross_country_freight_solutions.rb +408 -0
  69. data/lib/freight_kit/carriers/crowley.rb +10 -0
  70. data/lib/freight_kit/carriers/csa_transportation.rb +40 -0
  71. data/lib/freight_kit/carriers/csx_transportation.rb +40 -0
  72. data/lib/freight_kit/carriers/custom_global_logistics.rb +14 -0
  73. data/lib/freight_kit/carriers/d_and_a_transport.rb +10 -0
  74. data/lib/freight_kit/carriers/dak_transport.rb +10 -0
  75. data/lib/freight_kit/carriers/dash_courier_and_logistics_north_carolina.rb +10 -0
  76. data/lib/freight_kit/carriers/daylight_transport.rb +29 -0
  77. data/lib/freight_kit/carriers/dayton_freight_lines.rb +30 -0
  78. data/lib/freight_kit/carriers/dbr_logistics.rb +10 -0
  79. data/lib/freight_kit/carriers/deep_south_freight.rb +27 -0
  80. data/lib/freight_kit/carriers/delta_express.rb +10 -0
  81. data/lib/freight_kit/carriers/delta_transport.rb +10 -0
  82. data/lib/freight_kit/carriers/delta_trucking_logistics.rb +10 -0
  83. data/lib/freight_kit/carriers/demco_express.rb +10 -0
  84. data/lib/freight_kit/carriers/dependable_global_express.rb +10 -0
  85. data/lib/freight_kit/carriers/dependable_hawaiian_express.rb +24 -0
  86. data/lib/freight_kit/carriers/dependable_highway_express.rb +573 -0
  87. data/lib/freight_kit/carriers/desert_coastal_transport.rb +10 -0
  88. data/lib/freight_kit/carriers/dhl.rb +11 -0
  89. data/lib/freight_kit/carriers/diamond_line_delivery.rb +174 -0
  90. data/lib/freight_kit/carriers/ding_tai_trucking.rb +10 -0
  91. data/lib/freight_kit/carriers/diversified_transfer_and_storage.rb +29 -0
  92. data/lib/freight_kit/carriers/dohrn_transfer_company.rb +30 -0
  93. data/lib/freight_kit/carriers/dot_line_transportation.rb +29 -0
  94. data/lib/freight_kit/carriers/drt_transportation.rb +13 -0
  95. data/lib/freight_kit/carriers/dugan_truck_line.rb +29 -0
  96. data/lib/freight_kit/carriers/dupont.rb +10 -0
  97. data/lib/freight_kit/carriers/e_transport_carriers.rb +29 -0
  98. data/lib/freight_kit/carriers/echo_global_logistics.rb +13 -0
  99. data/lib/freight_kit/carriers/ecklund_logistics.rb +10 -0
  100. data/lib/freight_kit/carriers/el_emplumado_transport.rb +10 -0
  101. data/lib/freight_kit/carriers/elite_carriers.rb +28 -0
  102. data/lib/freight_kit/carriers/emerald_express.rb +10 -0
  103. data/lib/freight_kit/carriers/era_transport.rb +10 -0
  104. data/lib/freight_kit/carriers/estes_express_lines.rb +25 -0
  105. data/lib/freight_kit/carriers/euro_kam.rb +28 -0
  106. data/lib/freight_kit/carriers/ew_riverside_trucking.rb +10 -0
  107. data/lib/freight_kit/carriers/express_2000_inc.rb +12 -0
  108. data/lib/freight_kit/carriers/express_services_international.rb +10 -0
  109. data/lib/freight_kit/carriers/f_and_a_express.rb +27 -0
  110. data/lib/freight_kit/carriers/fairmont_logistics.rb +13 -0
  111. data/lib/freight_kit/carriers/fargo_cargo.rb +10 -0
  112. data/lib/freight_kit/carriers/fast_freight_transportation.rb +10 -0
  113. data/lib/freight_kit/carriers/fast_load_transport.rb +10 -0
  114. data/lib/freight_kit/carriers/fed_ex_express.rb +30 -0
  115. data/lib/freight_kit/carriers/fed_ex_ground.rb +24 -0
  116. data/lib/freight_kit/carriers/fed_ex_ltl_economy.rb +11 -0
  117. data/lib/freight_kit/carriers/fed_ex_ltl_priority.rb +11 -0
  118. data/lib/freight_kit/carriers/first_trucking_express.rb +10 -0
  119. data/lib/freight_kit/carriers/flash_trucking.rb +10 -0
  120. data/lib/freight_kit/carriers/fort_transportation_and_service_company_inc.rb +37 -0
  121. data/lib/freight_kit/carriers/forward_air.rb +781 -0
  122. data/lib/freight_kit/carriers/frahtex.rb +10 -0
  123. data/lib/freight_kit/carriers/frozen_food_express.rb +10 -0
  124. data/lib/freight_kit/carriers/gholia_bros_trucking.rb +36 -0
  125. data/lib/freight_kit/carriers/global_cargo.rb +10 -0
  126. data/lib/freight_kit/carriers/global_logistics_and_transportation.rb +10 -0
  127. data/lib/freight_kit/carriers/gls_freight.rb +32 -0
  128. data/lib/freight_kit/carriers/go_trucking_services.rb +10 -0
  129. data/lib/freight_kit/carriers/gold_eagle_transportation.rb +11 -0
  130. data/lib/freight_kit/carriers/golden_drop_trucking.rb +10 -0
  131. data/lib/freight_kit/carriers/gonzalez_transportation.rb +10 -0
  132. data/lib/freight_kit/carriers/gps_transport.rb +10 -0
  133. data/lib/freight_kit/carriers/greene_enterprise.rb +10 -0
  134. data/lib/freight_kit/carriers/gsa_international.rb +10 -0
  135. data/lib/freight_kit/carriers/gsp_express.rb +24 -0
  136. data/lib/freight_kit/carriers/gsv_transportation.rb +10 -0
  137. data/lib/freight_kit/carriers/gta_transportation.rb +10 -0
  138. data/lib/freight_kit/carriers/guam_freight_services.rb +10 -0
  139. data/lib/freight_kit/carriers/harrah_transportation.rb +23 -0
  140. data/lib/freight_kit/carriers/her_trucking.rb +10 -0
  141. data/lib/freight_kit/carriers/hercules_freight.rb +20 -0
  142. data/lib/freight_kit/carriers/highlander_xpress.rb +36 -0
  143. data/lib/freight_kit/carriers/hn_transport.rb +10 -0
  144. data/lib/freight_kit/carriers/honolulu_freight_service.rb +10 -0
  145. data/lib/freight_kit/carriers/hot_line_freight_system_inc.rb +12 -0
  146. data/lib/freight_kit/carriers/hotshot_freight_of_texas.rb +13 -0
  147. data/lib/freight_kit/carriers/houser_transport.rb +27 -0
  148. data/lib/freight_kit/carriers/infiniti_freight_logistics.rb +28 -0
  149. data/lib/freight_kit/carriers/infinity_trucking.rb +10 -0
  150. data/lib/freight_kit/carriers/interstate_tma.rb +10 -0
  151. data/lib/freight_kit/carriers/intrade_industries.rb +10 -0
  152. data/lib/freight_kit/carriers/jasper_trucking.rb +28 -0
  153. data/lib/freight_kit/carriers/jb_hunt.rb +11 -0
  154. data/lib/freight_kit/carriers/jfj_transportation.rb +8 -8
  155. data/lib/freight_kit/carriers/jkb_express.rb +10 -0
  156. data/lib/freight_kit/carriers/jlm_transport.rb +10 -0
  157. data/lib/freight_kit/carriers/johansson_transport.rb +10 -0
  158. data/lib/freight_kit/carriers/jones_express.rb +10 -0
  159. data/lib/freight_kit/carriers/jp_logistics.rb +41 -0
  160. data/lib/freight_kit/carriers/just_in_time_cargo.rb +29 -0
  161. data/lib/freight_kit/carriers/kengkok_times.rb +10 -0
  162. data/lib/freight_kit/carriers/kings_express.rb +10 -0
  163. data/lib/freight_kit/carriers/klc_transportation.rb +10 -0
  164. data/lib/freight_kit/carriers/km_trucking.rb +10 -0
  165. data/lib/freight_kit/carriers/kma_logistics.rb +10 -0
  166. data/lib/freight_kit/carriers/krc_logistics.rb +10 -0
  167. data/lib/freight_kit/carriers/ktx.rb +10 -0
  168. data/lib/freight_kit/carriers/landstar.rb +25 -0
  169. data/lib/freight_kit/carriers/lanter_distributing_llc.rb +30 -0
  170. data/lib/freight_kit/carriers/ld_trucking.rb +10 -0
  171. data/lib/freight_kit/carriers/legacy_logistics_solutions.rb +10 -0
  172. data/lib/freight_kit/carriers/leonards_express.rb +10 -0
  173. data/lib/freight_kit/carriers/liberty_linehaul_west.rb +28 -0
  174. data/lib/freight_kit/carriers/liberty_transport.rb +10 -0
  175. data/lib/freight_kit/carriers/lightning_express.rb +10 -0
  176. data/lib/freight_kit/carriers/lj_express.rb +24 -0
  177. data/lib/freight_kit/carriers/lkp_enterprises.rb +10 -0
  178. data/lib/freight_kit/carriers/ltl_pros.rb +28 -0
  179. data/lib/freight_kit/carriers/m_and_m_and_sons.rb +10 -0
  180. data/lib/freight_kit/carriers/mag_lines_transport.rb +10 -0
  181. data/lib/freight_kit/carriers/magic_messenger.rb +24 -0
  182. data/lib/freight_kit/carriers/majors_transit.rb +10 -0
  183. data/lib/freight_kit/carriers/map_global_logistics.rb +10 -0
  184. data/lib/freight_kit/carriers/matths_trucking.rb +11 -0
  185. data/lib/freight_kit/carriers/mav_canadian_transport.rb +13 -0
  186. data/lib/freight_kit/carriers/mc_systems.rb +35 -0
  187. data/lib/freight_kit/carriers/mega_fleet.rb +10 -0
  188. data/lib/freight_kit/carriers/mega_trans_group.rb +28 -0
  189. data/lib/freight_kit/carriers/meta_express.rb +10 -0
  190. data/lib/freight_kit/carriers/mia_transportation.rb +10 -0
  191. data/lib/freight_kit/carriers/midwest_motor_express.rb +14 -0
  192. data/lib/freight_kit/carriers/midwest_transport_and_trucking.rb +10 -0
  193. data/lib/freight_kit/carriers/mikade_delivery_service.rb +10 -0
  194. data/lib/freight_kit/carriers/mohoff_freight_lines.rb +23 -0
  195. data/lib/freight_kit/carriers/montata_travelers_express.rb +10 -0
  196. data/lib/freight_kit/carriers/morgan_van_lines.rb +29 -0
  197. data/lib/freight_kit/carriers/moto_transportation.rb +24 -0
  198. data/lib/freight_kit/carriers/mountain_valley_express.rb +197 -0
  199. data/lib/freight_kit/carriers/ms_freight.rb +27 -0
  200. data/lib/freight_kit/carriers/mvg_transport.rb +10 -0
  201. data/lib/freight_kit/carriers/n_and_m_transfer_co_inc.rb +29 -0
  202. data/lib/freight_kit/carriers/nabot_transport_solutions.rb +10 -0
  203. data/lib/freight_kit/carriers/national_freight_xpress.rb +10 -0
  204. data/lib/freight_kit/carriers/navigation_group.rb +10 -0
  205. data/lib/freight_kit/carriers/nelson_trucking.rb +10 -0
  206. data/lib/freight_kit/carriers/network_1_transportation.rb +10 -0
  207. data/lib/freight_kit/carriers/new_century_transport.rb +28 -0
  208. data/lib/freight_kit/carriers/new_penn_motor_express.rb +11 -0
  209. data/lib/freight_kit/carriers/nieves_transportation.rb +10 -0
  210. data/lib/freight_kit/carriers/nolan_transportation_group.rb +26 -0
  211. data/lib/freight_kit/carriers/northland_trucking.rb +10 -0
  212. data/lib/freight_kit/carriers/northwest_carrier_logistics.rb +27 -0
  213. data/lib/freight_kit/carriers/nt_usa.rb +10 -0
  214. data/lib/freight_kit/carriers/nu_line_transportation.rb +10 -0
  215. data/lib/freight_kit/carriers/numark_transportation.rb +80 -0
  216. data/lib/freight_kit/carriers/nvk_transport.rb +10 -0
  217. data/lib/freight_kit/carriers/ny_transport.rb +10 -0
  218. data/lib/freight_kit/carriers/oak_harbor.rb +28 -0
  219. data/lib/freight_kit/carriers/oakline_transportation.rb +10 -0
  220. data/lib/freight_kit/carriers/old_dominion_freight_line.rb +30 -0
  221. data/lib/freight_kit/carriers/on_trac.rb +555 -0
  222. data/lib/freight_kit/carriers/one_hundred_one_transport.rb +10 -0
  223. data/lib/freight_kit/carriers/one_way_delivery.rb +10 -0
  224. data/lib/freight_kit/carriers/oracle_transportation_solutions.rb +10 -0
  225. data/lib/freight_kit/carriers/orange_courier.rb +27 -0
  226. data/lib/freight_kit/carriers/ortas_trucking.rb +10 -0
  227. data/lib/freight_kit/carriers/pac_trux_transportation.rb +10 -0
  228. data/lib/freight_kit/carriers/pacer.rb +10 -0
  229. data/lib/freight_kit/carriers/pacific_logistics.rb +10 -0
  230. data/lib/freight_kit/carriers/pacific_states_truck_lines.rb +10 -0
  231. data/lib/freight_kit/carriers/paradise_distributing.rb +10 -0
  232. data/lib/freight_kit/carriers/paramount_freight_systems.rb +10 -0
  233. data/lib/freight_kit/carriers/peninsula_truck_lines.rb +206 -0
  234. data/lib/freight_kit/carriers/pg_transport.rb +10 -0
  235. data/lib/freight_kit/carriers/pgs_360.rb +10 -0
  236. data/lib/freight_kit/carriers/pilot_freight_services.rb +10 -0
  237. data/lib/freight_kit/carriers/pious_trans.rb +27 -0
  238. data/lib/freight_kit/carriers/pitt_ohio_express.rb +30 -0
  239. data/lib/freight_kit/carriers/pki_logistics.rb +12 -0
  240. data/lib/freight_kit/carriers/plana_transportation.rb +28 -0
  241. data/lib/freight_kit/carriers/prestige.rb +10 -0
  242. data/lib/freight_kit/carriers/pro_trans_solutions.rb +28 -0
  243. data/lib/freight_kit/carriers/puma_logistics.rb +10 -0
  244. data/lib/freight_kit/carriers/pwc_international.rb +10 -0
  245. data/lib/freight_kit/carriers/quality_logistics.rb +10 -0
  246. data/lib/freight_kit/carriers/queen_star_trucking.rb +27 -0
  247. data/lib/freight_kit/carriers/r_and_l_carriers.rb +11 -0
  248. data/lib/freight_kit/carriers/rac_transport.rb +10 -0
  249. data/lib/freight_kit/carriers/re_logistics.rb +23 -0
  250. data/lib/freight_kit/carriers/reddaway.rb +11 -0
  251. data/lib/freight_kit/carriers/reefer_van_network.rb +13 -0
  252. data/lib/freight_kit/carriers/refrigerated_trucking_and_ltl_transportation_services.rb +10 -0
  253. data/lib/freight_kit/carriers/ridgeline_express.rb +10 -0
  254. data/lib/freight_kit/carriers/rist_transport.rb +29 -0
  255. data/lib/freight_kit/carriers/river_city_transport.rb +10 -0
  256. data/lib/freight_kit/carriers/roadrunner_transportation_services.rb +669 -0
  257. data/lib/freight_kit/carriers/roadtex.rb +13 -0
  258. data/lib/freight_kit/carriers/ronald_transport_services.rb +10 -0
  259. data/lib/freight_kit/carriers/rose_trucking.rb +24 -0
  260. data/lib/freight_kit/carriers/rp_and_j_transport.rb +24 -0
  261. data/lib/freight_kit/carriers/rpm_transportation.rb +11 -0
  262. data/lib/freight_kit/carriers/rude_transportation.rb +30 -0
  263. data/lib/freight_kit/carriers/s_and_s_logistics.rb +10 -0
  264. data/lib/freight_kit/carriers/saia.rb +456 -362
  265. data/lib/freight_kit/carriers/sb_transportation.rb +27 -0
  266. data/lib/freight_kit/carriers/schneider_national.rb +29 -0
  267. data/lib/freight_kit/carriers/schwarz_trucking.rb +10 -0
  268. data/lib/freight_kit/carriers/sewell_motor_express.rb +29 -0
  269. data/lib/freight_kit/carriers/shawnee_trucking.rb +28 -0
  270. data/lib/freight_kit/carriers/shi_logistics.rb +10 -0
  271. data/lib/freight_kit/carriers/sinbad_transport.rb +10 -0
  272. data/lib/freight_kit/carriers/skyway.rb +10 -0
  273. data/lib/freight_kit/carriers/smith_cargo_transportation_services.rb +23 -0
  274. data/lib/freight_kit/carriers/sna_transportation.rb +10 -0
  275. data/lib/freight_kit/carriers/solid_group.rb +10 -0
  276. data/lib/freight_kit/carriers/solution_carrier_express.rb +10 -0
  277. data/lib/freight_kit/carriers/southeastern_freight_lines.rb +441 -0
  278. data/lib/freight_kit/carriers/southwestern_motor_transport.rb +30 -0
  279. data/lib/freight_kit/carriers/span_alaska.rb +10 -0
  280. data/lib/freight_kit/carriers/specialize_transportation.rb +27 -0
  281. data/lib/freight_kit/carriers/ssi_refrigerated_express.rb +10 -0
  282. data/lib/freight_kit/carriers/standard_forwarding_llc.rb +28 -0
  283. data/lib/freight_kit/carriers/star_american_enterprise.rb +10 -0
  284. data/lib/freight_kit/carriers/sterling_transportation.rb +10 -0
  285. data/lib/freight_kit/carriers/stg.rb +163 -0
  286. data/lib/freight_kit/carriers/supervan_service.rb +10 -0
  287. data/lib/freight_kit/carriers/sutton_transport_inc.rb +12 -0
  288. data/lib/freight_kit/carriers/swift_transportation.rb +28 -0
  289. data/lib/freight_kit/carriers/t_force_worldwide.rb +605 -0
  290. data/lib/freight_kit/carriers/tax_airfreight_inc.rb +35 -0
  291. data/lib/freight_kit/carriers/tforce_freight_inc.rb +30 -0
  292. data/lib/freight_kit/carriers/the_custom_companies.rb +162 -0
  293. data/lib/freight_kit/carriers/thk_trucking.rb +28 -0
  294. data/lib/freight_kit/carriers/tiger_cool_express.rb +11 -0
  295. data/lib/freight_kit/carriers/tili_logistics.rb +10 -0
  296. data/lib/freight_kit/carriers/tmt_industries.rb +10 -0
  297. data/lib/freight_kit/carriers/top_ten_express.rb +28 -0
  298. data/lib/freight_kit/carriers/total_quality_logistics.rb +339 -0
  299. data/lib/freight_kit/carriers/total_transportation.rb +258 -0
  300. data/lib/freight_kit/carriers/trans_international_trucking.rb +29 -0
  301. data/lib/freight_kit/carriers/treasure_transportation.rb +10 -0
  302. data/lib/freight_kit/carriers/tri_state_services.rb +10 -0
  303. data/lib/freight_kit/carriers/tritex_freighters.rb +10 -0
  304. data/lib/freight_kit/carriers/triways.rb +10 -0
  305. data/lib/freight_kit/carriers/tsi_kansas.rb +29 -0
  306. data/lib/freight_kit/carriers/u_and_r_transportation.rb +23 -0
  307. data/lib/freight_kit/carriers/union_pacific.rb +11 -0
  308. data/lib/freight_kit/carriers/united_freight_logistics.rb +10 -0
  309. data/lib/freight_kit/carriers/unlimited_distance_transportation.rb +10 -0
  310. data/lib/freight_kit/carriers/up_streamline.rb +10 -0
  311. data/lib/freight_kit/carriers/ups_freight.rb +12 -0
  312. data/lib/freight_kit/carriers/us_freightways.rb +10 -0
  313. data/lib/freight_kit/carriers/usa_truck.rb +28 -0
  314. data/lib/freight_kit/carriers/usf_holland.rb +11 -0
  315. data/lib/freight_kit/carriers/valley_cartage.rb +11 -0
  316. data/lib/freight_kit/carriers/vc_transport.rb +10 -0
  317. data/lib/freight_kit/carriers/vision_express.rb +11 -0
  318. data/lib/freight_kit/carriers/vision_logistics_group.rb +10 -0
  319. data/lib/freight_kit/carriers/vmg_transportation_group.rb +10 -0
  320. data/lib/freight_kit/carriers/volpe_express.rb +10 -0
  321. data/lib/freight_kit/carriers/ward_trucking.rb +29 -0
  322. data/lib/freight_kit/carriers/wdwb.rb +10 -0
  323. data/lib/freight_kit/carriers/western_flyer_express.rb +28 -0
  324. data/lib/freight_kit/carriers/western_regional_delivery_service.rb +265 -0
  325. data/lib/freight_kit/carriers/western_specialized_trucking.rb +22 -0
  326. data/lib/freight_kit/carriers/win_distribution.rb +28 -0
  327. data/lib/freight_kit/carriers/wlb_transport.rb +10 -0
  328. data/lib/freight_kit/carriers/x_trux.rb +29 -0
  329. data/lib/freight_kit/carriers/xpo_logistics.rb +415 -0
  330. data/lib/freight_kit/carriers/xpress_global_systems.rb +30 -0
  331. data/lib/freight_kit/carriers/xylo_trucking.rb +10 -0
  332. data/lib/freight_kit/carriers/yrc_freight.rb +24 -0
  333. data/lib/freight_kit/carriers/zentner_transportation.rb +28 -0
  334. data/lib/freight_kit/carriers.rb +331 -34
  335. data/lib/freight_kit/countries.rb +22 -0
  336. data/lib/freight_kit/error.rb +0 -2
  337. data/lib/freight_kit/errors/document_not_found_error.rb +0 -2
  338. data/lib/freight_kit/errors/expired_credentials_error.rb +0 -2
  339. data/lib/freight_kit/errors/http_error.rb +0 -2
  340. data/lib/freight_kit/errors/invalid_credentials_error.rb +0 -2
  341. data/lib/freight_kit/errors/rate_limit_error.rb +12 -0
  342. data/lib/freight_kit/errors/response_error.rb +0 -2
  343. data/lib/freight_kit/errors/shipment_not_found_error.rb +0 -2
  344. data/lib/freight_kit/errors/unserviceable_accessorials_error.rb +1 -5
  345. data/lib/freight_kit/errors/unserviceable_error.rb +0 -2
  346. data/lib/freight_kit/helpers/documentable.rb +0 -2
  347. data/lib/freight_kit/helpers/pickupable.rb +3 -14
  348. data/lib/freight_kit/helpers/rateable.rb +0 -2
  349. data/lib/freight_kit/helpers/trackable.rb +0 -2
  350. data/lib/freight_kit/http_client/cache_store.rb +2 -4
  351. data/lib/freight_kit/http_client/httpi_adapter.rb +37 -0
  352. data/lib/freight_kit/http_client/log_device.rb +0 -2
  353. data/lib/freight_kit/http_client/response.rb +0 -2
  354. data/lib/freight_kit/http_client/revalidation.rb +0 -2
  355. data/lib/freight_kit/http_client/safe_retries.rb +17 -3
  356. data/lib/freight_kit/http_client/zstd.rb +2 -4
  357. data/lib/freight_kit/http_client.rb +21 -21
  358. data/lib/freight_kit/model.rb +1 -3
  359. data/lib/freight_kit/models/address.rb +15 -0
  360. data/lib/freight_kit/models/contact.rb +3 -4
  361. data/lib/freight_kit/models/country.rb +20 -0
  362. data/lib/freight_kit/models/credential.rb +3 -18
  363. data/lib/freight_kit/models/date_time.rb +0 -2
  364. data/lib/freight_kit/models/document_response.rb +0 -2
  365. data/lib/freight_kit/models/label.rb +0 -2
  366. data/lib/freight_kit/models/location.rb +10 -25
  367. data/lib/freight_kit/models/pickup_response.rb +0 -2
  368. data/lib/freight_kit/models/price.rb +0 -2
  369. data/lib/freight_kit/models/rate.rb +0 -2
  370. data/lib/freight_kit/models/rate_response.rb +0 -2
  371. data/lib/freight_kit/models/region.rb +19 -0
  372. data/lib/freight_kit/models/response.rb +0 -2
  373. data/lib/freight_kit/models/shipment.rb +5 -14
  374. data/lib/freight_kit/models/shipment_event.rb +0 -2
  375. data/lib/freight_kit/models/terminal.rb +10 -0
  376. data/lib/freight_kit/models/tracking_response.rb +0 -2
  377. data/lib/freight_kit/package.rb +52 -64
  378. data/lib/freight_kit/package_item.rb +14 -14
  379. data/lib/freight_kit/packaging.rb +6 -26
  380. data/lib/freight_kit/platform.rb +0 -32
  381. data/lib/freight_kit/platforms/carrier_logistics.rb +326 -345
  382. data/lib/freight_kit/platforms/dsdc.rb +82 -0
  383. data/lib/freight_kit/platforms/next_tms/graphql_client/mutation/quote_create.rb +32 -0
  384. data/lib/freight_kit/platforms/next_tms/graphql_client/mutation/shipment_create.rb +29 -0
  385. data/lib/freight_kit/platforms/next_tms/graphql_client/query/broker_carrier.rb +37 -0
  386. data/lib/freight_kit/platforms/next_tms/graphql_client/query/broker_carriers.rb +45 -0
  387. data/lib/freight_kit/platforms/next_tms/graphql_client/query/broker_customer.rb +54 -0
  388. data/lib/freight_kit/platforms/next_tms/graphql_client/query/broker_customers.rb +62 -0
  389. data/lib/freight_kit/platforms/next_tms/graphql_client/query/carrier.rb +22 -0
  390. data/lib/freight_kit/platforms/next_tms/graphql_client/query/carriers.rb +30 -0
  391. data/lib/freight_kit/platforms/next_tms/graphql_client/query/customer.rb +20 -0
  392. data/lib/freight_kit/platforms/next_tms/graphql_client/query/customers.rb +28 -0
  393. data/lib/freight_kit/platforms/next_tms/graphql_client/query/invoice.rb +31 -0
  394. data/lib/freight_kit/platforms/next_tms/graphql_client/query/invoices.rb +39 -0
  395. data/lib/freight_kit/platforms/next_tms/graphql_client/query/shipment.rb +102 -0
  396. data/lib/freight_kit/platforms/next_tms/graphql_client/query/shipment_documents.rb +29 -0
  397. data/lib/freight_kit/platforms/next_tms/graphql_client/query/shipments.rb +110 -0
  398. data/lib/freight_kit/platforms/next_tms/graphql_client.rb +22 -0
  399. data/lib/freight_kit/platforms/next_tms/orm/address.rb +22 -0
  400. data/lib/freight_kit/platforms/next_tms/orm/base.rb +120 -0
  401. data/lib/freight_kit/platforms/next_tms/orm/broker_carrier.rb +18 -0
  402. data/lib/freight_kit/platforms/next_tms/orm/broker_customer.rb +22 -0
  403. data/lib/freight_kit/platforms/next_tms/orm/carrier.rb +14 -0
  404. data/lib/freight_kit/platforms/next_tms/orm/collection.rb +335 -0
  405. data/lib/freight_kit/platforms/next_tms/orm/customer.rb +12 -0
  406. data/lib/freight_kit/platforms/next_tms/orm/invoice.rb +21 -0
  407. data/lib/freight_kit/platforms/next_tms/orm/record_not_found_error.rb +9 -0
  408. data/lib/freight_kit/platforms/next_tms/orm/shipment.rb +50 -0
  409. data/lib/freight_kit/platforms/next_tms/orm.rb +38 -0
  410. data/lib/freight_kit/platforms/next_tms.rb +452 -0
  411. data/lib/freight_kit/platforms/the_great_information_factory.rb +492 -425
  412. data/lib/freight_kit/regions.rb +27 -0
  413. data/lib/freight_kit/shipment_packer.rb +36 -38
  414. data/lib/freight_kit/tariff/overlength_rule.rb +1 -5
  415. data/lib/freight_kit/tariff.rb +0 -2
  416. data/lib/freight_kit.rb +103 -11
  417. data/schemas/next_tms.json +110710 -0
  418. metadata +443 -55
  419. data/configuration/carriers/abfs.yml +0 -124
  420. data/configuration/carriers/btvp.yml +0 -84
  421. data/configuration/carriers/ccyq.yml +0 -121
  422. data/configuration/carriers/clni.yml +0 -113
  423. data/configuration/carriers/cnwy.yml +0 -113
  424. data/configuration/carriers/ctbv.yml +0 -117
  425. data/configuration/carriers/dcha.yml +0 -105
  426. data/configuration/carriers/dlds.yml +0 -111
  427. data/configuration/carriers/dphe.yml +0 -130
  428. data/configuration/carriers/drrq.yml +0 -131
  429. data/configuration/carriers/fcsy.yml +0 -102
  430. data/configuration/carriers/fwda.yml +0 -137
  431. data/configuration/carriers/jfj_transportation.yml +0 -2
  432. data/configuration/carriers/mtvl.yml +0 -12
  433. data/configuration/carriers/numk.yml +0 -14
  434. data/configuration/carriers/otcl.yml +0 -124
  435. data/configuration/carriers/pens.yml +0 -22
  436. data/configuration/carriers/rdfs.yml +0 -142
  437. data/configuration/carriers/saia.yml +0 -129
  438. data/configuration/carriers/sefl.yml +0 -115
  439. data/configuration/carriers/totl.yml +0 -111
  440. data/configuration/carriers/tqyl.yml +0 -28
  441. data/configuration/carriers/wrds.yml +0 -20
  442. data/configuration/platforms/carrier_logistics.yml +0 -25
  443. data/configuration/platforms/next.yml +0 -12
  444. data/configuration/platforms/the_great_information_factory.yml +0 -122
  445. data/lib/freight_kit/carriers/abfs.rb +0 -421
  446. data/lib/freight_kit/carriers/btvp.rb +0 -29
  447. data/lib/freight_kit/carriers/ccyq.rb +0 -310
  448. data/lib/freight_kit/carriers/clni.rb +0 -396
  449. data/lib/freight_kit/carriers/cnwy.rb +0 -327
  450. data/lib/freight_kit/carriers/ctbv.rb +0 -53
  451. data/lib/freight_kit/carriers/dcha.rb +0 -76
  452. data/lib/freight_kit/carriers/dlds.rb +0 -49
  453. data/lib/freight_kit/carriers/dphe.rb +0 -472
  454. data/lib/freight_kit/carriers/drrq.rb +0 -580
  455. data/lib/freight_kit/carriers/fcsy.rb +0 -57
  456. data/lib/freight_kit/carriers/fwda.rb +0 -744
  457. data/lib/freight_kit/carriers/mtvl.rb +0 -34
  458. data/lib/freight_kit/carriers/numk.rb +0 -58
  459. data/lib/freight_kit/carriers/otcl.rb +0 -520
  460. data/lib/freight_kit/carriers/pens.rb +0 -204
  461. data/lib/freight_kit/carriers/rdfs.rb +0 -521
  462. data/lib/freight_kit/carriers/sefl.rb +0 -342
  463. data/lib/freight_kit/carriers/totl.rb +0 -172
  464. data/lib/freight_kit/carriers/tqyl.rb +0 -337
  465. data/lib/freight_kit/carriers/wrds.rb +0 -246
  466. data/lib/freight_kit/platforms/next.rb +0 -101
@@ -1,527 +1,594 @@
1
- # frozen_string_literal: true
2
-
3
1
  module FreightKit
4
- class TheGreatInformationFactory < Platform
5
- class << self
6
- def required_credential_types
7
- %i[api]
8
- end
2
+ module Platforms
3
+ class TheGreatInformationFactory < Platform
4
+ class << self
5
+ def mappable_accessorials
6
+ {
7
+ appointment_delivery: 'NOTFEE',
8
+ inside_delivery: 'INSDEL',
9
+ liftgate_delivery: 'LIFDEL',
10
+ liftgate_pickup: 'LIFPIC',
11
+ mall_delivery: 'INSDEL',
12
+ residential_delivery: 'RESDEL',
13
+ residential_pickup: 'RESPIC',
14
+ restaurant_delivery: 'INSDEL'
15
+ }
16
+ end
9
17
 
10
- def requirements
11
- %i[credentials tariff]
12
- end
18
+ def overlength_fees_require_tariff? = true
19
+ def required_credential_types = %i[api]
20
+ def requirements = %i[credentials tariff]
21
+ def services = %i[standard]
22
+
23
+ def unquotable_accessorials
24
+ %i[
25
+ athletic_facility_delivery
26
+ athletic_facility_pickup
27
+ cemetery_delivery
28
+ cemetery_pickup
29
+ church_delivery
30
+ church_pickup
31
+ construction_delivery
32
+ construction_pickup
33
+ dock_dropoff
34
+ dock_pickup
35
+ farm_delivery
36
+ farm_pickup
37
+ fitness_center_delivery
38
+ fitness_center_pickup
39
+ flatbed_delivery
40
+ flatbed_pickup
41
+ golf_course_delivery
42
+ golf_course_pickup
43
+ government_delivery
44
+ government_pickup
45
+ grocery_store_delivery
46
+ grocery_store_pickup
47
+ holiday_delivery
48
+ holiday_pickup
49
+ hospital_delivery
50
+ hospital_pickup
51
+ hotel_delivery
52
+ hotel_pickup
53
+ inspection_site_delivery
54
+ inspection_site_pickup
55
+ jobsite_delivery
56
+ jobsite_pickup
57
+ military_site_delivery
58
+ military_site_pickup
59
+ mine_site_delivery
60
+ mine_site_pickup
61
+ motel_delivery
62
+ motel_pickup
63
+ nursing_home_delivery
64
+ nursing_home_pickup
65
+ park_delivery
66
+ park_pickup
67
+ prison_delivery
68
+ prison_pickup
69
+ ranch_delivery
70
+ ranch_pickup
71
+ reservation_delivery
72
+ reservation_pickup
73
+ resort_delivery
74
+ resort_pickup
75
+ restaurant_pickup
76
+ school_delivery
77
+ school_pickup
78
+ steel_mill_delivery
79
+ steel_mill_pickup
80
+ storage_facility_delivery
81
+ storage_facility_pickup
82
+ university_delivery
83
+ university_pickup
84
+ utility_site_delivery
85
+ utility_site_pickup
86
+ ]
87
+ end
13
88
 
14
- def overlength_fees_require_tariff?
15
- true
89
+ def unserviceable_accessorials
90
+ %i[
91
+ afterhours_delivery
92
+ airport_delivery
93
+ airport_pickup
94
+ amusement_park_delivery
95
+ amusement_park_pickup
96
+ appointment_pickup
97
+ brewery_delivery
98
+ brewery_pickup
99
+ convention_delivery
100
+ convention_pickup
101
+ customs_brokerage
102
+ driver_assist
103
+ early_morning_delivery
104
+ fair_delivery
105
+ fair_pickup
106
+ grocery_warehouse_delivery
107
+ grocery_warehouse_pickup
108
+ guaranteed_delivery
109
+ guaranteed_delivery_am
110
+ guaranteed_delivery_pm
111
+ inside_pickup
112
+ marina_delivery
113
+ marina_pickup
114
+ saturday_delivery
115
+ saturday_pickup
116
+ sunday_delivery
117
+ sunday_pickup
118
+ winery_delivery
119
+ winery_pickup
120
+ ]
121
+ end
16
122
  end
17
- end
18
-
19
- REACTIVE_FREIGHT_PLATFORM = true
20
123
 
21
- include FreightKit::Rateable
22
- include FreightKit::Trackable
23
- include FreightKit::Pickupable
124
+ include FreightKit::Rateable
125
+ include FreightKit::Trackable
126
+ include FreightKit::Pickupable
127
+
128
+ API = { actions: { rates: :getquote, track: :tracktrace, pickup: :requestpickup }, use_ssl: { rates: false, track: false } }.freeze
129
+ EVENTS = {
130
+ types: {
131
+ arrived_at_terminal: 'arrived',
132
+ delivered: 'delivered',
133
+ departed: 'departed',
134
+ out_for_delivery: 'out for delvry',
135
+ pickup_information_sent_to_carrier: 'p/u dispatched'
136
+ }
137
+ }.freeze
24
138
 
25
- protected
139
+ protected
26
140
 
27
- def wrap_request(request)
28
- { 'arg0' => request }
29
- end
141
+ def build_calculated_accessorials(_packages) = []
30
142
 
31
- def build_soap_header
32
- api_credentials = fetch_credential(:api)
143
+ def build_location(city, province)
144
+ Location.new(city: city.titleize, province: province.upcase, country: ActiveUtils::Country.find('USA'))
145
+ end
33
146
 
34
- { username: api_credentials.username, password: api_credentials.password }
35
- end
147
+ def build_pickup_request(
148
+ delivery_from:,
149
+ delivery_to:,
150
+ dispatcher:,
151
+ pickup_from:,
152
+ pickup_to:,
153
+ scac:,
154
+ service:,
155
+ shipment:
156
+ )
157
+ shipper_phone = shipment.origin.contact.phone.gsub(/\s+/, '').gsub(/[()-+.]/, '')
158
+ shipper_phone = shipper_phone[1..] if shipper_phone.length == 11
159
+
160
+ request = {
161
+ securityinfo: build_soap_header,
162
+ shipperinfo: {
163
+ name: shipment.origin.contact.company_name,
164
+ contact: shipment.origin.contact.name,
165
+ phonenumber: shipper_phone,
166
+ address1: shipment.origin.address1,
167
+ address2: shipment.origin.address2,
168
+ city: shipment.origin.city,
169
+ state: shipment.origin.province,
170
+ ReadyDate: pickup_from.strftime('%m/%d/%Y'),
171
+ ReadyTime: pickup_from.strftime('%H%M').to_i,
172
+ CloseTime: pickup_to.strftime('%H%M').to_i,
173
+ zip: shipment.origin.postal_code,
174
+ SpecialInstructions: ''
175
+ },
176
+ ShipmentCount: 1,
177
+ shipments: [
178
+ {
179
+ DestZip: shipment.destination.postal_code,
180
+ Pieces: shipment.packages.sum(&:quantity),
181
+ Pallets: shipment.packages.select { |p| p.packaging.pallet? }.sum(&:quantity),
182
+ Weight: shipment.packages.sum { |p| p.pounds(:total).ceil },
183
+ HAZ: shipment.packages.any?(&:hazmat?) ? 'Y' : 'N',
184
+ dblStack: 'N',
185
+ SortSeg: 'N',
186
+ Pro: shipment.pro,
187
+ Liftgate: shipment.accessorials.include?(:liftgate_pickup) ? 'Y' : 'N'
188
+ }
189
+ ]
190
+ }
36
191
 
37
- def commit(action, request)
38
- client_args = {
39
- wsdl: build_url(action),
40
- convert_request_keys_to: :upcase,
41
- env_namespace: :soapenv
42
- }
43
-
44
- call_args = {
45
- headers: { 'SOAPAction' => '""' },
46
- soap_action: false,
47
- message: request
48
- }
49
-
50
- ::FreightKit::SoapClient.new(
51
- carrier: self,
52
- action:,
53
- client_args:,
54
- call_args:,
55
- soap_operation: @conf.dig(:api, :actions, action),
56
- ).call
57
- end
192
+ request = wrap_request(request)
193
+ save_request(request)
58
194
 
59
- def parse_api_date(date)
60
- return if date.blank?
195
+ request
196
+ end
61
197
 
62
- local_date = ::Date.strptime(date, '%m/%d/%Y')
63
- ::FreightKit::DateTime.new(local_date:)
64
- end
198
+ def build_rate_request(shipment:)
199
+ accessorials = []
65
200
 
66
- def parse_api_date_time(date_time, location)
67
- return if date_time.blank?
201
+ if shipment.accessorials.present?
202
+ serviceable_accessorials?(shipment.accessorials)
68
203
 
69
- format = date_time.include?('-') ? '%Y-%m-%d %H:%M' : '%m/%d/%Y %H:%M'
204
+ accessorials = shipment
205
+ .accessorials
206
+ .select { |accessorial| unserviceable_accessorials.exclude?(accessorial) }
207
+ .map { |accessorial| mappable_accessorials[accessorial] }
208
+ end
70
209
 
71
- local_date_time = ::Time.strptime(date_time, format).to_fs(:db)
72
- ::FreightKit::DateTime.new(local_date_time:, location:)
73
- end
210
+ accessorials += build_calculated_accessorials(shipment.packages)
211
+ accessorials.uniq!
212
+
213
+ item = shipment.packages.map do |package|
214
+ {
215
+ _class: package.freight_class,
216
+ description: (package.description || 'Freight')[..8].upcase,
217
+ haz: (package.hazmat? ? 'Y' : ''),
218
+ pallets: (package.packaging.pallet? ? package.quantity : 0),
219
+ pieces: package.quantity,
220
+ weight: package.pounds(:total).ceil
221
+ }
222
+ end
74
223
 
75
- def build_url(action)
76
- scheme = @conf.dig(:api, :use_ssl, action) ? 'https://' : 'http://'
77
- domain = @conf.dig(:api, :domains, action).presence || @conf.dig(:api, :domain)
78
- port = @conf.dig(:api, :ports, action)
79
- return [scheme, domain, @conf.dig(:api, :endpoints, action)].join unless port
224
+ request = {
225
+ securityinfo: build_soap_header,
226
+ quote: {
227
+ iam: 'D', # S for shipper, C for consignee, D for third party
228
+ shipper: {
229
+ city: shipment.origin.city.upcase,
230
+ state: shipment.origin.province.upcase,
231
+ zip: shipment.origin.postal_code.gsub(/\s+/, '').upcase
232
+ },
233
+ consignee: {
234
+ city: shipment.destination.city.upcase,
235
+ state: shipment.destination.province.upcase,
236
+ zip: shipment.destination.postal_code.gsub(/\s+/, '').upcase
237
+ },
238
+ accessorialcount: accessorials.count,
239
+ accessorial: accessorials.map { |code| { code: } },
240
+ ppdcol: 'P', # Prepaid
241
+ itemcount: shipment.packages.sum(&:quantity),
242
+ item:
243
+ }
244
+ }
80
245
 
81
- "#{scheme}#{domain}:#{port}#{@conf.dig(:api, :endpoints, action)}"
82
- end
246
+ request = wrap_request(request)
247
+ save_request(request)
83
248
 
84
- def strip_date(str)
85
- str ? str.split(/[A|P]M /)[1] : nil
86
- end
249
+ request
250
+ end
87
251
 
88
- # Rates
252
+ def build_soap_header
253
+ api_credentials = fetch_credential(:api)
89
254
 
90
- def build_calculated_accessorials(packages)
91
- []
92
- end
255
+ { username: api_credentials.username, password: api_credentials.password }
256
+ end
93
257
 
94
- def build_rate_request(shipment:)
95
- accessorials = []
258
+ def build_tracking_request(tracking_number)
259
+ request = { pronumber: tracking_number, securityinfo: build_soap_header }
96
260
 
97
- if shipment.accessorials.present?
98
- serviceable_accessorials?(shipment.accessorials)
261
+ request = wrap_request(request)
262
+ save_request(request)
99
263
 
100
- accessorials = shipment
101
- .accessorials
102
- .select { |accessorial| @conf.dig(:accessorials, :unserviceable).exclude?(accessorial) }
103
- .map { |accessorial| @conf.dig(:accessorials, :mappable, accessorial) }
264
+ request
104
265
  end
105
266
 
106
- accessorials += build_calculated_accessorials(shipment.packages)
107
- accessorials.uniq!
108
-
109
- item = shipment.packages.map do |package|
110
- {
111
- _class: package.freight_class,
112
- description: (package.description || 'Freight')[..8].upcase,
113
- haz: (package.hazmat? ? 'Y' : ''),
114
- pallets: (package.packaging.pallet? ? package.quantity : 0),
115
- pieces: package.quantity,
116
- weight: package.pounds(:total).ceil
117
- }
118
- end
267
+ def build_url(action)
268
+ scheme = self.class::API.dig(:use_ssl, action) ? 'https://' : 'http://'
269
+ domain = self.class::API.dig(:domains, action).presence || self.class::API[:domain]
270
+ port = self.class::API.dig(:ports, action)
271
+ return [scheme, domain, self.class::API.dig(:endpoints, action)].join unless port
119
272
 
120
- request = {
121
- securityinfo: build_soap_header,
122
- quote: {
123
- iam: 'D', # S for shipper, C for consignee, D for third party
124
- shipper: {
125
- city: shipment.origin.city.upcase,
126
- state: shipment.origin.province.upcase,
127
- zip: shipment.origin.postal_code.gsub(/\s+/, '').upcase
128
- },
129
- consignee: {
130
- city: shipment.destination.city.upcase,
131
- state: shipment.destination.province.upcase,
132
- zip: shipment.destination.postal_code.gsub(/\s+/, '').upcase
133
- },
134
- accessorialcount: accessorials.count,
135
- accessorial: accessorials.map { |code| { code: } },
136
- ppdcol: 'P', # Prepaid
137
- itemcount: shipment.packages.sum(&:quantity),
138
- item:
139
- }
140
- }
141
-
142
- request = wrap_request(request)
143
- save_request(request)
144
-
145
- request
146
- end
273
+ "#{scheme}#{domain}:#{port}#{self.class::API.dig(:endpoints, action)}"
274
+ end
147
275
 
148
- def rate_item_description(rate_item)
149
- description = rate_item[:description] || ''
150
- description = description.gsub('-', '')
151
- description = description.squish
152
- description = description.sub('disc.on', 'discount on')
153
- description = description.capitalize
154
- description = description.sub('zip code', 'ZIP code')
155
- description.sub('Zip code', 'ZIP code')
156
- end
276
+ def commit(action, request)
277
+ client_args = { wsdl: build_url(action), convert_request_keys_to: :upcase, env_namespace: :soapenv }
157
278
 
158
- def parse_rate_response(shipment:, response:)
159
- rate_response = RateResponse.new(request: last_request, response:)
279
+ call_args = { headers: { 'SOAPAction' => '""' }, soap_action: false, message: request }
160
280
 
161
- if response.blank?
162
- rate_response.error = ResponseError.new('Unknown response')
163
- return rate_response
281
+ ::FreightKit::SoapClient.new(
282
+ carrier: self,
283
+ action:,
284
+ client_args:,
285
+ call_args:,
286
+ soap_operation: self.class::API.dig(:actions, action)
287
+ ).call
164
288
  end
165
289
 
166
- error_code = response.dig(:getquote_response, :return, :rating, :errorcode)
167
- if error_code
168
- rate_response.error = parse_error_response(error_code)
169
- return rate_response
290
+ def parse_api_date(date)
291
+ return if date.blank?
292
+
293
+ local_date = ::Date.strptime(date, '%m/%d/%Y')
294
+ ::FreightKit::DateTime.new(local_date:)
170
295
  end
171
296
 
172
- total_cents = response.dig(:getquote_response, :return, :rating, :amount)
297
+ def parse_api_date_time(date_time, location)
298
+ return if date_time.blank?
173
299
 
174
- raise FreightKit::ResponseError, 'API Error: Cost is empty' if total_cents.blank?
300
+ format = date_time.include?('-') ? '%Y-%m-%d %H:%M' : '%m/%d/%Y %H:%M'
175
301
 
176
- rate_items = response.dig(:getquote_response, :return, :rateitem)
177
- total_cents = (total_cents.to_f * 100).to_i
302
+ local_date_time = ::Time.strptime(date_time, format).to_fs(:db)
303
+ ::FreightKit::DateTime.new(local_date_time:, location:)
304
+ end
178
305
 
179
- prices = []
306
+ def parse_document_response(type, tracking_number)
307
+ base_url = build_url(type)
308
+ website_credentials = fetch_credential(:api)
309
+ query_parameter = "&username=#{website_credentials.username}&" \
310
+ "password=#{website_credentials.password}&" \
311
+ "pronumber=#{tracking_number}&" \
312
+ 'format=PDF'
180
313
 
181
- # Confusing API sometimes returns lines of freight with high costs and then later includes includes lines that
182
- # override the high cost without adding a discount, etc
183
- rate_items.each do |rate_item|
184
- next if ['Sub Total', 'GrandTotal'].include?(rate_item[:acccode])
314
+ url = [base_url, query_parameter].join
185
315
 
186
- # Exclude lines that are just the packages repeated back to us
187
- next unless rate_item[:pallets] == '0' && rate_item[:pieces] == '0'
316
+ response = HTTPClient.get(url, proxy_url:)
188
317
 
189
- cents = (rate_item[:amount].to_f * 100).to_i
190
- description = rate_item_description(rate_item)
318
+ image = response.deep_symbolize_keys.dig(:ImageRequest, :Image)
319
+ image = image.last if image.is_a?(Array)
320
+ # ImageRequest[:Image] sometimes return an Array and both images are identical
191
321
 
192
- prices << Price.new(blame: :api, cents:, description:)
193
- end
322
+ document_response = DocumentResponse.new(request: url)
194
323
 
195
- # Since we expected the low-cost overriding lines earlier, we need to handle situations where those lines do not
196
- # appear
197
- if prices.sum(&:cents) < total_cents
198
- prices = [
199
- Price.new(
200
- blame: :api,
201
- cents: total_cents - prices.sum(&:cents),
202
- description: 'Freight',
203
- ),
204
- ] + prices
205
- end
324
+ unless image
325
+ document_response.error = DocumentNotFoundError.new
326
+ return document_response
327
+ end
206
328
 
207
- if self.class.overlength_fees_require_tariff?
208
- shipment.packages.each do |package|
209
- cents = overlength_fee(tariff, package)
210
- next unless cents.positive?
329
+ base64_document_data = image.dig(:ImageData, :__content__)
211
330
 
212
- prices << Price.new(
213
- blame: :tariff,
214
- cents:,
215
- description: 'Overlength fee',
216
- )
331
+ unless base64_document_data
332
+ document_response.error = DocumentNotFoundError.new
333
+ return document_response
217
334
  end
218
- end
219
335
 
220
- transit_days = response.dig(
221
- :getquote_response,
222
- :return,
223
- :service,
224
- :days,
225
- ).to_i
336
+ decoded_pdf_data = Base64.decode64(base64_document_data)
337
+ document_response.assign_attributes(content_type: 'application/pdf', data: decoded_pdf_data)
226
338
 
227
- # Calculate real transit time based on information we have about the destination service days
228
- %i[mon tue wed thu fri].each do |weekday|
229
- transit_days += 1 if response.dig(:getquote_response, :return, :service, :destination, weekday) == 'N'
339
+ document_response
230
340
  end
231
341
 
232
- estimate_reference = response.dig(
233
- :getquote_response,
234
- :return,
235
- :rating,
236
- :quotenumber,
237
- )
238
-
239
- rate = Rate.new(
240
- carrier_name: self.class.name,
241
- carrier: self,
242
- currency: 'USD',
243
- estimate_reference:,
244
- prices:,
245
- scac: self.class.scac.upcase,
246
- service_name: :standard,
247
- shipment:,
248
- transit_days:,
249
- with_excessive_length_fees: @conf.dig(:attributes, :rates, :with_excessive_length_fees),
250
- )
251
-
252
- rate_response.rates = [rate]
253
- rate_response
254
- end
342
+ def parse_error_response(error_code)
343
+ case error_code
344
+ when 'BADUSRPWD' then InvalidCredentialsError.new
345
+ when 'NOSVC' then UnserviceableError.new('Origin or destination has no service available')
346
+ when 'BADCONZIP' then UnserviceableError.new('Invalid destination ZIP code')
347
+ else
348
+ ResponseError.new("API error code #{error_code}")
349
+ end
350
+ end
255
351
 
256
- # Tracking
352
+ def parse_location(code)
353
+ country = ActiveUtils::Country.find('USA')
354
+ return Location.new(country:) unless code
257
355
 
258
- def build_tracking_request(tracking_number)
259
- request = { pronumber: tracking_number, securityinfo: build_soap_header }
356
+ location = self.class::EVENTS.dig(:locations, code.to_sym)
260
357
 
261
- request = wrap_request(request)
262
- save_request(request)
358
+ if location
359
+ Location.new(city: location[:city], province: location[:state], country:)
360
+ else
361
+ Location.new(city: code, country:)
362
+ end
363
+ end
263
364
 
264
- request
265
- end
365
+ def parse_pickup_response(response)
366
+ pickup_response = PickupResponse.new(request: last_request, response:)
266
367
 
267
- def parse_location(code)
268
- country = ActiveUtils::Country.find('USA')
269
- return Location.new(country:) unless code
368
+ result = response.dig(:requestpickup_response, :return, :results)
369
+ if result[:errorcode]
370
+ pickup_response.error = FreightKit::ResponseError.new("API Error: #{result[:errorcode]}")
371
+ return pickup_response
372
+ end
270
373
 
271
- location = @conf.dig(:events, :locations, code.to_sym)
374
+ pickup_number = result[:pickupnumber]
272
375
 
273
- if location
274
- Location.new(
275
- city: location[:city],
276
- province: location[:state],
277
- country:,
278
- )
279
- else
280
- Location.new(city: code, country:)
281
- end
282
- end
376
+ if pickup_number == '0'
377
+ pickup_response.error = FreightKit::ResponseError.new('Unknown Error')
378
+ return pickup_response
379
+ end
283
380
 
284
- def parse_error_response(error_code)
285
- case error_code
286
- when 'BADUSRPWD' then InvalidCredentialsError.new
287
- when 'NOSVC' then UnserviceableError.new('Origin or destination has no service available')
288
- when 'BADCONZIP' then UnserviceableError.new('Invalid destination ZIP code')
289
- else
290
- ResponseError.new("API error code #{error_code}")
381
+ pickup_response.pickup_number = pickup_number
382
+ pickup_response
291
383
  end
292
- end
293
384
 
294
- def build_location(city, province)
295
- Location.new(city: city.titleize, province: province.upcase, country: ActiveUtils::Country.find('USA'))
296
- end
385
+ def parse_rate_response(shipment:, response:)
386
+ rate_response = RateResponse.new(request: last_request, response:)
297
387
 
298
- def parse_tracking_response(response)
299
- tracking_response = TrackingResponse.new(carrier: self, request: last_request, response:)
300
- mapped_response = response.dig(:tracktrace_response, :return, :currentstatus)
301
-
302
- if mapped_response[:errorcode]
303
- tracking_response.error = parse_error_response(mapped_response[:errorcode])
304
- return tracking_response
305
- end
388
+ if response.blank?
389
+ rate_response.error = ResponseError.new('Unknown response')
390
+ return rate_response
391
+ end
306
392
 
307
- receiver_location = build_location(
308
- mapped_response.dig(:consignee, :city),
309
- mapped_response.dig(:consignee, :state),
310
- )
311
- shipper_location = build_location(mapped_response.dig(:shipper, :city), mapped_response.dig(:shipper, :state))
393
+ error_code = response.dig(:getquote_response, :return, :rating, :errorcode)
394
+ if error_code
395
+ rate_response.error = parse_error_response(error_code)
396
+ return rate_response
397
+ end
312
398
 
313
- actual_delivery_date = mapped_response[:deliverydate]
399
+ total_cents = response.dig(:getquote_response, :return, :rating, :amount)
314
400
 
315
- if actual_delivery_date.present?
316
- comment = mapped_response[:status].downcase
401
+ raise FreightKit::ResponseError, 'API Error: Cost is empty' if total_cents.blank?
317
402
 
318
- if comment.starts_with?('delivered')
319
- api_date = comment.downcase.split('signed')[0].split('on')[1].strip.sub('at ', '')
320
- actual_delivery_date = parse_api_date(api_date)
321
- end
322
- end
403
+ rate_items = response.dig(:getquote_response, :return, :rateitem)
404
+ total_cents = (total_cents.to_f * 100).to_i
323
405
 
324
- shipment_events = []
406
+ prices = []
325
407
 
326
- ship_time = parse_api_date(mapped_response[:shipdate])
327
- # Leave this open for modification later
328
- picked_up_event = ShipmentEvent.new(location: shipper_location, date_time: ship_time, type_code: :picked_up)
408
+ # Confusing API sometimes returns lines of freight with high costs and then later includes includes lines that
409
+ # override the high cost without adding a discount, etc
410
+ rate_items.each do |rate_item|
411
+ next if ['Sub Total', 'GrandTotal'].include?(rate_item[:acccode])
329
412
 
330
- scheduled_delivery_date = parse_api_date(mapped_response[:estdeliverydate])
331
- tracking_number = response.dig(:tracktrace_response, :return, :pronumber)
413
+ # Exclude lines that are just the packages repeated back to us
414
+ next unless rate_item[:pallets] == '0' && rate_item[:pieces] == '0'
332
415
 
333
- api_events = response.dig(:tracktrace_response, :return, :history)
334
- api_events = [api_events] if api_events.is_a?(Hash)
416
+ cents = (rate_item[:amount].to_f * 100).to_i
417
+ description = rate_item_description(rate_item)
335
418
 
336
- last_location = nil
419
+ prices << Price.new(blame: :api, cents:, description:)
420
+ end
337
421
 
338
- api_events.each_with_index do |api_event, index|
339
- next if api_event[:description].blank?
422
+ # Since we expected the low-cost overriding lines earlier, we need to handle situations where those lines do not
423
+ # appear
424
+ if prices.sum(&:cents) < total_cents
425
+ prices = [Price.new(blame: :api, cents: total_cents - prices.sum(&:cents), description: 'Freight')] + prices
426
+ end
340
427
 
341
- event = nil
342
- @conf.dig(:events, :types).each do |key, val|
343
- next if api_event[:description].downcase.exclude?(val)
428
+ if self.class.overlength_fees_require_tariff?
429
+ shipment.packages.each do |package|
430
+ cents = overlength_fee(tariff, package)
431
+ next unless cents.positive?
344
432
 
345
- event = key
346
- break
433
+ prices << Price.new(blame: :tariff, cents:, description: 'Overlength fee')
434
+ end
347
435
  end
348
- next if event.blank?
349
436
 
350
- location = if api_event[:location].blank?
351
- case event
352
- when :departed then last_location
353
- when :picked_up, :pickup_information_sent_to_carrier then shipper_location
354
- when :delivered, :out_for_delivery then receiver_location
355
- end
356
- else
357
- parse_location(api_event[:location])
358
- end
359
-
360
- api_date_time = "#{api_event[:date]} #{api_event[:time]}"
361
- date_time = api_event[:date].present? ? parse_api_date_time(api_date_time, location) : nil
362
-
363
- case event
364
- when :arrived_at_terminal
365
- # Duplicate event occurs without location data from API
366
- break if api_event[:location].blank?
367
- when :delivered
368
- actual_delivery_date = date_time
369
- when :out_for_delivery
370
- # Do not consider out for delivery when out for delivery and interlined dates match
371
- next_api_event = api_events[index + 1]
372
-
373
- break if next_api_event.blank?
374
-
375
- if next_api_event[:description].include?('INTERLINE') && next_api_event[:date] == api_event[:date]
376
- shipment_events << ShipmentEvent.new(date_time:, location:, type_code: :departed)
377
- next
378
- end
379
- when :pickup_information_sent_to_carrier
380
- # Pickup event appears after carrier information sent, let's fix that
381
- picked_up_event.date_time = date_time.dup
437
+ transit_days = response.dig(:getquote_response, :return, :service, :days).to_i
438
+
439
+ # Calculate real transit time based on information we have about the destination service days
440
+ %i[mon tue wed thu fri].each do |weekday|
441
+ transit_days += 1 if response.dig(:getquote_response, :return, :service, :destination, weekday) == 'N'
382
442
  end
383
443
 
384
- last_location = location
444
+ estimate_reference = response.dig(:getquote_response, :return, :rating, :quotenumber)
445
+
446
+ rate = Rate.new(
447
+ carrier_name: name,
448
+ carrier: self,
449
+ currency: 'USD',
450
+ estimate_reference:,
451
+ prices:,
452
+ scac:,
453
+ service_name: :standard,
454
+ shipment:,
455
+ transit_days:,
456
+ with_excessive_length_fees: rates_with_excessive_length_fees?
457
+ )
385
458
 
386
- shipment_events << ShipmentEvent.new(date_time:, location:, type_code: event)
459
+ rate_response.rates = [rate]
460
+ rate_response
387
461
  end
388
462
 
389
- shipment_events << picked_up_event
463
+ def parse_tracking_response(response)
464
+ tracking_response = TrackingResponse.new(carrier: self, request: last_request, response:)
465
+ mapped_response = response.dig(:tracktrace_response, :return, :currentstatus)
390
466
 
391
- if shipment_events.collect(&:date_time).none?(nil)
392
- shipment_events = shipment_events.sort_by do |shipment_event|
393
- d = shipment_event.date_time
394
- d&.local_date_time || d.date_time_with_zone&.to_fs(:db) || d.local_date&.to_fs(:db)
467
+ if mapped_response[:errorcode]
468
+ tracking_response.error = parse_error_response(mapped_response[:errorcode])
469
+ return tracking_response
395
470
  end
396
- end
397
471
 
398
- status = shipment_events.last&.type_code
399
-
400
- # Workarounds for false status on certain events when timestamps are in wrong order
401
- status = :out_for_delivery if shipment_events.find do |shipment_event|
402
- shipment_event.type_code == :out_for_delivery
403
- end
404
- status = :delivered if shipment_events.find { |shipment_event| shipment_event.type_code == :delivered }
405
-
406
- tracking_response.assign_attributes(
407
- actual_delivery_date:,
408
- destination: receiver_location,
409
- origin: shipper_location,
410
- scheduled_delivery_date:,
411
- ship_time:,
412
- shipment_events:,
413
- status:,
414
- tracking_number:,
415
- )
472
+ receiver_location = build_location(mapped_response.dig(:consignee, :city), mapped_response.dig(:consignee, :state))
473
+ shipper_location = build_location(mapped_response.dig(:shipper, :city), mapped_response.dig(:shipper, :state))
416
474
 
417
- tracking_response
418
- end
475
+ actual_delivery_date = mapped_response[:deliverydate]
419
476
 
420
- def parse_pickup_response(response)
421
- pickup_response = PickupResponse.new(request: last_request, response:)
477
+ if actual_delivery_date.present?
478
+ comment = mapped_response[:status].downcase
422
479
 
423
- result = response.dig(:requestpickup_response, :return, :results)
424
- if result[:errorcode]
425
- pickup_response.error = FreightKit::ResponseError.new("API Error: #{result[:errorcode]}")
426
- return pickup_response
427
- end
480
+ if comment.starts_with?('delivered')
481
+ api_date = comment.downcase.split('signed')[0].split('on')[1].strip.sub('at ', '')
482
+ actual_delivery_date = parse_api_date(api_date)
483
+ end
484
+ end
428
485
 
429
- pickup_number = result[:pickupnumber]
486
+ shipment_events = []
430
487
 
431
- if pickup_number == '0'
432
- pickup_response.error = FreightKit::ResponseError.new('Unknown Error')
433
- return pickup_response
434
- end
488
+ ship_time = parse_api_date(mapped_response[:shipdate])
489
+ # Leave this open for modification later
490
+ picked_up_event = ShipmentEvent.new(location: shipper_location, date_time: ship_time, type_code: :picked_up)
435
491
 
436
- pickup_response.pickup_number = pickup_number
437
- pickup_response
438
- end
492
+ scheduled_delivery_date = parse_api_date(mapped_response[:estdeliverydate])
493
+ tracking_number = response.dig(:tracktrace_response, :return, :pronumber)
439
494
 
440
- def build_pickup_request(
441
- delivery_from:,
442
- delivery_to:,
443
- dispatcher:,
444
- pickup_from:,
445
- pickup_to:,
446
- scac:,
447
- service:,
448
- shipment:
449
- )
450
- shipper_phone = shipment.origin.contact.phone.gsub(/\s+/, '').gsub(/[()-+.]/, '')
451
- shipper_phone = shipper_phone[1..] if shipper_phone.length == 11
452
-
453
- request = {
454
- securityinfo: build_soap_header,
455
- shipperinfo: {
456
- name: shipment.origin.contact.company_name,
457
- contact: shipment.origin.contact.name,
458
- phonenumber: shipper_phone,
459
- address1: shipment.origin.address1,
460
- address2: shipment.origin.address2,
461
- city: shipment.origin.city,
462
- state: shipment.origin.province,
463
- ReadyDate: pickup_from.strftime('%m/%d/%Y'),
464
- ReadyTime: pickup_from.strftime('%H%M').to_i,
465
- CloseTime: pickup_to.strftime('%H%M').to_i,
466
- zip: shipment.origin.postal_code,
467
- SpecialInstructions: ''
468
- },
469
- ShipmentCount: 1,
470
- shipments: [
471
- {
472
- DestZip: shipment.destination.postal_code,
473
- Pieces: shipment.packages.sum(&:quantity),
474
- Pallets: shipment.packages.select { |p| p.packaging.pallet? }.sum(&:quantity),
475
- Weight: shipment.packages.sum { |p| p.pounds(:total).ceil },
476
- HAZ: shipment.packages.any?(&:hazmat?) ? 'Y' : 'N',
477
- dblStack: 'N',
478
- SortSeg: 'N',
479
- Pro: shipment.pro,
480
- Liftgate: shipment.accessorials.include?(:liftgate_pickup) ? 'Y' : 'N'
481
- },
482
- ]
483
- }
484
-
485
- request = wrap_request(request)
486
- save_request(request)
487
-
488
- request
489
- end
495
+ api_events = response.dig(:tracktrace_response, :return, :history)
496
+ api_events = [api_events] if api_events.is_a?(Hash)
497
+
498
+ last_location = nil
490
499
 
491
- def parse_document_response(type, tracking_number)
492
- base_url = build_url(type)
493
- website_credentials = fetch_credential(:api)
494
- query_parameter = "&username=#{website_credentials.username}&" \
495
- "password=#{website_credentials.password}&" \
496
- "pronumber=#{tracking_number}&" \
497
- 'format=PDF'
500
+ api_events.each_with_index do |api_event, index|
501
+ next if api_event[:description].blank?
498
502
 
499
- url = [base_url, query_parameter].join
503
+ event = nil
504
+ self.class::EVENTS[:types].each do |key, val|
505
+ next if api_event[:description].downcase.exclude?(val)
500
506
 
501
- response = HTTPClient.get(url)
507
+ event = key
508
+ break
509
+ end
510
+ next if event.blank?
511
+
512
+ location = if api_event[:location].blank?
513
+ case event
514
+ when :departed then last_location
515
+ when :picked_up, :pickup_information_sent_to_carrier then shipper_location
516
+ when :delivered, :out_for_delivery then receiver_location
517
+ end
518
+ else
519
+ parse_location(api_event[:location])
520
+ end
502
521
 
503
- image = response.deep_symbolize_keys.dig(:ImageRequest, :Image)
504
- image = image.last if image.is_a?(Array)
505
- # ImageRequest[:Image] sometimes return an Array and both images are identical
522
+ api_date_time = "#{api_event[:date]} #{api_event[:time]}"
523
+ date_time = api_event[:date].present? ? parse_api_date_time(api_date_time, location) : nil
524
+
525
+ case event
526
+ when :arrived_at_terminal
527
+ # Duplicate event occurs without location data from API
528
+ break if api_event[:location].blank?
529
+ when :delivered
530
+ actual_delivery_date = date_time
531
+ when :out_for_delivery
532
+ # Do not consider out for delivery when out for delivery and interlined dates match
533
+ next_api_event = api_events[index + 1]
534
+
535
+ break if next_api_event.blank?
536
+
537
+ if next_api_event[:description].include?('INTERLINE') && next_api_event[:date] == api_event[:date]
538
+ shipment_events << ShipmentEvent.new(date_time:, location:, type_code: :departed)
539
+ next
540
+ end
541
+ when :pickup_information_sent_to_carrier
542
+ # Pickup event appears after carrier information sent, let's fix that
543
+ picked_up_event.date_time = date_time.dup
544
+ end
506
545
 
507
- document_response = DocumentResponse.new(request: url)
546
+ last_location = location
508
547
 
509
- unless image
510
- document_response.error = DocumentNotFoundError.new
511
- return document_response
512
- end
548
+ shipment_events << ShipmentEvent.new(date_time:, location:, type_code: event)
549
+ end
513
550
 
514
- base64_document_data = image.dig(:ImageData, :__content__)
551
+ shipment_events << picked_up_event
515
552
 
516
- unless base64_document_data
517
- document_response.error = DocumentNotFoundError.new
518
- return document_response
553
+ if shipment_events.collect(&:date_time).none?(nil)
554
+ shipment_events = shipment_events.sort_by do |shipment_event|
555
+ d = shipment_event.date_time
556
+ d&.local_date_time || d.date_time_with_zone&.to_fs(:db) || d.local_date&.to_fs(:db)
557
+ end
558
+ end
559
+
560
+ status = shipment_events.last&.type_code
561
+
562
+ # Workarounds for false status on certain events when timestamps are in wrong order
563
+ status = :out_for_delivery if shipment_events.find { |shipment_event| shipment_event.type_code == :out_for_delivery }
564
+ status = :delivered if shipment_events.find { |shipment_event| shipment_event.type_code == :delivered }
565
+
566
+ tracking_response.assign_attributes(
567
+ actual_delivery_date:,
568
+ destination: receiver_location,
569
+ origin: shipper_location,
570
+ scheduled_delivery_date:,
571
+ ship_time:,
572
+ shipment_events:,
573
+ status:,
574
+ tracking_number:
575
+ )
576
+
577
+ tracking_response
519
578
  end
520
579
 
521
- decoded_pdf_data = Base64.decode64(base64_document_data)
522
- document_response.assign_attributes(content_type: 'application/pdf', data: decoded_pdf_data)
580
+ def rate_item_description(rate_item)
581
+ description = rate_item[:description] || ''
582
+ description = description.gsub('-', '')
583
+ description = description.squish
584
+ description = description.sub('disc.on', 'discount on')
585
+ description = description.capitalize
586
+ description = description.sub('zip code', 'ZIP code')
587
+ description.sub('Zip code', 'ZIP code')
588
+ end
523
589
 
524
- document_response
590
+ def strip_date(str) = str ? str.split(/[A|P]M /)[1] : nil
591
+ def wrap_request(request) = { 'arg0' => request }
525
592
  end
526
593
  end
527
594
  end