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,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  module FreightKit
4
2
  # Carrier is the abstract base class for all supported carriers.
5
3
  #
@@ -7,7 +5,6 @@ module FreightKit
7
5
  # implement all the methods that the carrier supports.
8
6
  #
9
7
  # @see #create_pickup
10
- # @see #cancel_shipment
11
8
  # @see #find_tracking_info
12
9
  # @see #find_rates
13
10
  #
@@ -16,32 +13,45 @@ module FreightKit
16
13
  # @see #save_request
17
14
  class Carrier
18
15
  class << self
16
+ # Whether the carrier is a broker that hands shipments to other carriers.
17
+ # @return [Boolean]
18
+ def acts_as_broker? = false
19
+
19
20
  # Whether bill of lading (BOL) requires tracking number at time of pickup.
20
21
  # @return [Boolean]
21
- def bol_requires_tracking_number?
22
- false
23
- end
22
+ def bol_requires_tracking_number? = false
24
23
 
25
- # The default location to use for {#valid_credentials?}.
26
- # @return [FreightKit::Location]
27
- def default_location
28
- Location.new(
29
- address1: '455 N. Rexford Dr.',
30
- address2: '3rd Floor',
31
- city: 'Beverly Hills',
32
- country: 'US',
33
- fax: '1-310-275-8159',
34
- phone: '1-310-285-1013',
35
- state: 'CA',
36
- zip: '90210',
37
- )
38
- end
24
+ # The carrier's addresses for mailing checks, so applications need not enter them for each customer.
25
+ # @return [Array<FreightKit::Address>]
26
+ def check_mailing_addresses = []
27
+
28
+ # Whether the carrier's bill of lading (BOL) and proof of delivery (POD) are the same document.
29
+ # @return [Boolean]
30
+ def consider_bol_and_pod_documents_same? = false
31
+
32
+ # The carrier's department contacts, so applications need not enter them for each customer.
33
+ # @return [Array<FreightKit::Contact>]
34
+ def contacts = []
35
+
36
+ # Whether {#create_pickup} is implemented.
37
+ # @return [Boolean]
38
+ def create_pickup_implemented? = implemented?(:create_pickup)
39
+
40
+ # Whether {#find_rates} is implemented.
41
+ # @return [Boolean]
42
+ def find_rates_implemented? = implemented?(:find_rates)
39
43
 
40
44
  # Whether finding rates with declared value (thus insurance) is implemented.
41
45
  # @return [Boolean]
42
- def find_rates_with_declared_value?
43
- false
44
- end
46
+ def find_rates_with_declared_value? = false
47
+
48
+ # The carrier's main office, from its public FMCSA registration.
49
+ # @return [FreightKit::Address, nil]
50
+ def headquarters = nil
51
+
52
+ # The carrier's permanent UUID. Applications store it to refer to the carrier, so never change or reuse one.
53
+ # @return [String]
54
+ def id = nil
45
55
 
46
56
  # Whether instance method is supported
47
57
  # @return [Boolean]
@@ -51,53 +61,111 @@ module FreightKit
51
61
  false
52
62
  end
53
63
 
54
- # The address field maximum length accepted by the carrier
55
- # @return [Integer]
56
- def maximum_address_field_length
57
- 255
64
+ # The carrier's registered legal name, with its entity suffix (e.g. "Saia Motor Freight Line LLC"), when known.
65
+ # {.name} is the name the carrier does business as.
66
+ # @return [String, nil]
67
+ def legal_name = nil
68
+
69
+ # The package's longest horizontal dimension (length or width), as a
70
+ # Measured::Length so comparisons stay unit-agnostic.
71
+ #
72
+ # @param package [FreightKit::Package]
73
+ # @return [Measured::Length]
74
+ def longest_dimension(package)
75
+ [Measured::Length.new(package.length(:inches), :inches), Measured::Length.new(package.width(:inches), :inches)].max
58
76
  end
59
77
 
78
+ # FreightKit accessorials the carrier prices, mapped to the carrier's codes.
79
+ # @return [Hash{Symbol => Object}]
80
+ def mappable_accessorials = {}
81
+
60
82
  # The maximum height the carrier will accept.
61
83
  # @return [Measured::Length]
62
- def maximum_height
63
- Measured::Length.new(105, :inches)
64
- end
84
+ def maximum_height = Measured::Length.new(105, :inches)
65
85
 
66
86
  # The maximum weight the carrier will accept.
67
87
  # @return [Measured::Weight]
68
- def maximum_weight
69
- Measured::Weight.new(10_000, :pounds)
70
- end
88
+ def maximum_weight = Measured::Weight.new(10_000, :pounds)
71
89
 
72
90
  # What length overlength fees the carrier begins charging at.
73
91
  # @return [Measured::Length]
74
- def minimum_length_for_overlength_fees
75
- Measured::Length.new(48, :inches)
92
+ def minimum_length_for_overlength_fees = Measured::Length.new(48, :inches)
93
+
94
+ # @param package [FreightKit::Package]
95
+ # @return [Boolean] whether the package is long enough to incur overlength fees.
96
+ def overlength?(package) = longest_dimension(package) >= minimum_length_for_overlength_fees
97
+
98
+ def overlength_fee(tariff, package)
99
+ overlength_rule = overlength_rule_for(tariff, package)
100
+ return 0 if overlength_rule.nil?
101
+
102
+ package.quantity * overlength_rule.fee_cents
76
103
  end
77
104
 
78
105
  # Whether or not the carrier quotes overlength fees via API.
79
106
  # @note Should the API not calculate these fees, they should be calculated some other way outside of FreightKit.
80
107
  # @return [Boolean]
81
- def overlength_fees_require_tariff?
82
- true
108
+ def overlength_fees_require_tariff? = true
109
+
110
+ # Returns the overlength rule from +tariff+ that applies to +package+, or
111
+ # +nil+ when the package is not overlength, or no configured rule covers it.
112
+ #
113
+ # This is the single source of truth for "does a rule cover this package?"
114
+ # shared by {#overlength_fee} and {#validate_packages} so the two can never
115
+ # disagree (e.g. a package quoting $0 overlength while also being treated as
116
+ # serviceable).
117
+ #
118
+ # @param tariff [FreightKit::Tariff, nil]
119
+ # @param package [FreightKit::Package]
120
+ # @return [FreightKit::Tariff::OverlengthRule, nil]
121
+ def overlength_rule_for(tariff, package)
122
+ return unless tariff.is_a?(FreightKit::Tariff) && overlength?(package)
123
+
124
+ tariff.overlength_rules.find { |overlength_rule| overlength_rule.cover?(longest_dimension(package)) }
83
125
  end
84
126
 
85
127
  # Whether carrier considers pickup number the same as the tracking number.
86
- def pickup_number_is_tracking_number?
87
- false
88
- end
128
+ def pickup_number_is_tracking_number? = false
129
+
130
+ # Whether the rates the carrier's API returns include excessive length fees. Carriers without rates, or that need
131
+ # a tariff to price overlength fees, return rates without them.
132
+ # @return [Boolean]
133
+ def rates_with_excessive_length_fees? = find_rates_implemented? && requirements.exclude?(:tariff)
134
+
135
+ # Returns the `Credential` methods (passed to `#initialize`) that cannot respond with blank values.
136
+ # @return [Array<Symbol>]
137
+ def required_credential_types = []
89
138
 
90
139
  # Returns the keywords passed to `#initialize` that cannot be blank.
91
140
  # @return [Array<Symbol>]
92
- def requirements
93
- []
141
+ def requirements = []
142
+
143
+ # @return [String, nil]
144
+ def scac = nil
145
+
146
+ # Raises {UnserviceableAccessorialsError} for accessorials the carrier refuses, or that it neither maps nor serves
147
+ # unpriced. Returns false when the carrier maps no accessorials.
148
+ # @return [Boolean]
149
+ def serviceable_accessorials?(accessorials)
150
+ return true if accessorials.blank?
151
+ return false if mappable_accessorials.blank?
152
+
153
+ refused = accessorials.select do |accessorial|
154
+ unserviceable_accessorials.include?(accessorial) ||
155
+ (mappable_accessorials.keys.exclude?(accessorial) && unquotable_accessorials.exclude?(accessorial))
156
+ end
157
+ raise FreightKit::UnserviceableAccessorialsError.new(accessorials: refused) if refused.any?
158
+
159
+ true
94
160
  end
95
161
 
96
- # Returns the `Credential` methods (passed to `#initialize`) that cannot respond with blank values.
162
+ # The services {#find_rates} quotes (e.g. `:standard`, `:guaranteed_delivery`).
97
163
  # @return [Array<Symbol>]
98
- def required_credential_types
99
- %i[api]
100
- end
164
+ def services = []
165
+
166
+ # The carrier's terminals, so applications need not enter them for each customer.
167
+ # @return [Array<FreightKit::Terminal>]
168
+ def terminals = []
101
169
 
102
170
  # The template URL for tracking one of carrier's `NUMBERS` publicly. A template URL is a URL containing the token
103
171
  # "%s" that can be replaced to generate a valid URL.
@@ -112,11 +180,29 @@ module FreightKit
112
180
  # @raise [ArgumentError]
113
181
  # @return [String, nil] The template URL or nil if no template is available for the given key.
114
182
  def tracking_url_template(key)
115
- raise ArgumentError, "key must be one of: #{NUMBERS.join(", ")}" if NUMBERS.exclude?(key)
183
+ raise ArgumentError, "key must be one of: #{NUMBERS.join(', ')}" if NUMBERS.exclude?(key)
116
184
 
117
- "#{self}::#{key.to_s.upcase}_TRACKING_URL_TEMPLATE".constantize
185
+ tracking_url_templates[key]
118
186
  end
119
187
 
188
+ # The template URLs for {.tracking_url_template}, by `NUMBERS` key.
189
+ # @return [Hash{Symbol => String}]
190
+ def tracking_url_templates = {}
191
+
192
+ # FreightKit accessorials the carrier serves but does not price.
193
+ # @return [Array<Symbol>]
194
+ def unquotable_accessorials = []
195
+
196
+ # FreightKit accessorials the carrier refuses.
197
+ # @return [Array<Symbol>]
198
+ def unserviceable_accessorials = []
199
+
200
+ # @return [Integer, nil]
201
+ def us_dot_number = nil
202
+
203
+ # @return [Integer, nil]
204
+ def us_mc_number = nil
205
+
120
206
  # Regular expression to use for validating carrier's `NUMBERS`.
121
207
  #
122
208
  # Returns the regular expression used for validating the carrier's number based on the provided `key`.
@@ -125,30 +211,85 @@ module FreightKit
125
211
  # @see `NUMBERS`
126
212
  # @param [Symbol] key The symbol representing the carrier number type for which the regular expression is needed.
127
213
  # @raise [ArgumentError] Raised if the provided key is not one of the specified carrier number types.
128
- # @return [Regexp] The regular expression for validating the specified carrier number type.
214
+ # @return [Regexp, nil] The regular expression for validating the specified carrier number type.
129
215
  def valid_number_regex(key)
130
- raise ArgumentError, "key must be one of: #{NUMBERS.join(", ")}" if NUMBERS.exclude?(key)
216
+ raise ArgumentError, "key must be one of: #{NUMBERS.join(', ')}" if NUMBERS.exclude?(key)
131
217
 
132
- "#{self}::VALID_#{key.to_s.upcase}_REGEX".constantize
218
+ valid_number_regexes[key]
133
219
  end
134
- end
135
220
 
136
- BOL_NUMBER_TRACKING_URL_TEMPLATE = nil
137
- ORDER_NUMBER_TRACKING_URL_TEMPLATE = nil
138
- PICKUP_NUMBER_TRACKING_URL_TEMPLATE = nil
139
- PO_NUMBER_TRACKING_URL_TEMPLATE = nil
140
- TRACKING_NUMBER_TRACKING_URL_TEMPLATE = nil
141
- VALID_BOL_NUMBER_REGEX = nil
142
- VALID_ORDER_NUMBER_REGEX = nil
143
- VALID_PICKUP_NUMBER_REGEX = nil
144
- VALID_PO_NUMBER_REGEX = nil
145
- VALID_TRACKING_NUMBER_REGEX = nil
221
+ # The regular expressions for {.valid_number_regex}, by `NUMBERS` key.
222
+ # @return [Hash{Symbol => Regexp}]
223
+ def valid_number_regexes = {}
224
+
225
+ # Determine whether the carrier will accept the packages based on credentials and/or tariff.
226
+ # @param packages [Array<FreightKit::Package>]
227
+ # @param tariff [FreightKit::Tariff]
228
+ # @return [Boolean]
229
+ def validate_packages(packages, tariff = nil)
230
+ return false if packages.blank?
231
+
232
+ message = []
233
+
234
+ max_height_inches = maximum_height.convert_to(:inches).value
235
+ if packages.map { |p| p.height(:inches) }.max > max_height_inches
236
+ message << "items must be #{max_height_inches.to_f} inches tall or less"
237
+ end
238
+
239
+ max_weight_pounds = maximum_weight.convert_to(:pounds).value
240
+ message << "items must weigh #{max_weight_pounds.to_f} lbs or less" if packages.sum { |p| p.pounds(:total) } > max_weight_pounds
241
+
242
+ # Carriers that don't quote overlength fees via their API rely on the
243
+ # tariff to price them. Fail closed rather than silently under-quoting: a
244
+ # missing, empty, or non-covering tariff for an overlength package must
245
+ # make the carrier unserviceable. We key off rule *coverage* (via
246
+ # #overlength_rule_for) rather than the tariff object's mere presence,
247
+ # because a present-but-empty FreightKit::Tariff is not `blank?` and would
248
+ # otherwise slip past this check.
249
+ if overlength_fees_require_tariff?
250
+ missing_dimensions = packages.any? do |package|
251
+ [package.height(:inches), package.length(:inches), package.width(:inches)].any?(&:zero?)
252
+ end
253
+
254
+ uncovered_overlength = packages.any? { |package| overlength?(package) && overlength_rule_for(tariff, package).nil? }
255
+
256
+ if missing_dimensions
257
+ message << 'item dimensions are required'
258
+ elsif uncovered_overlength
259
+ message << 'tariff must be defined to calculate overlength fees'
260
+ end
261
+ end
262
+
263
+ raise UnserviceableError, message.join(', ').capitalize if message.present?
264
+
265
+ true
266
+ end
267
+
268
+ # The carrier's homepage, verified to load over HTTPS and to name the carrier (e.g. "https://abf.com").
269
+ # @return [String, nil]
270
+ def website_url = nil
271
+ end
146
272
 
147
- NUMBERS = %i[bol_number order_number pickup_number po_number tracking_number]
273
+ NUMBERS = %i[bol_number order_number pickup_number po_number tracking_number].freeze
148
274
 
149
- attr_accessor :conf, :rates_with_excessive_length_fees, :tmpdir
150
275
  attr_reader :credentials, :customer_location, :last_request, :tariff
151
276
 
277
+ delegate :id,
278
+ :longest_dimension,
279
+ :mappable_accessorials,
280
+ :name,
281
+ :overlength?,
282
+ :overlength_fee,
283
+ :overlength_rule_for,
284
+ :rates_with_excessive_length_fees?,
285
+ :scac,
286
+ :serviceable_accessorials?,
287
+ :unquotable_accessorials,
288
+ :unserviceable_accessorials,
289
+ :valid_number_regex,
290
+ :validate_packages,
291
+ to: :class
292
+
152
293
  # @param credentials [Array<Credential>]
153
294
  # @param customer_location [Location]
154
295
  # @param tariff [Tariff]
@@ -156,14 +297,14 @@ module FreightKit
156
297
  credentials = [credentials] if credentials.is_a?(Credential)
157
298
 
158
299
  if credentials.map(&:class).uniq != [Credential]
159
- message = "#{self.class.name}#new: `credentials` must be a Credential or Array of Credential"
300
+ message = "#{name}#new: `credentials` must be a Credential or Array of Credential"
160
301
  raise ArgumentError, message
161
302
  end
162
303
 
163
304
  missing_credential_types = self.class.required_credential_types.uniq - credentials.map(&:type).uniq
164
305
 
165
306
  if missing_credential_types.any?
166
- message = "#{self.class.name}#new: `Credential` of type(s) missing: #{missing_credential_types.join(", ")}"
307
+ message = "#{name}#new: `Credential` of type(s) missing: #{missing_credential_types.join(', ')}"
167
308
  raise ArgumentError, message
168
309
  end
169
310
 
@@ -171,38 +312,17 @@ module FreightKit
171
312
 
172
313
  if customer_location.present?
173
314
  unless customer_location.is_a?(Location)
174
- message = "#{self.class.name}#new: `customer_location` must be a Location"
315
+ message = "#{name}#new: `customer_location` must be a Location"
175
316
  raise ArgumentError, message
176
317
  end
177
318
 
178
319
  @customer_location = customer_location
179
320
  end
180
321
 
181
- if tariff.present?
182
- raise ArgumentError, "#{self.class.name}#new: `tariff` must be a Tariff" unless tariff.is_a?(Tariff)
183
-
184
- @tariff = tariff
185
- end
186
-
187
- conf_path = File
188
- .join(
189
- File.expand_path(
190
- '../../../../configuration/carriers',
191
- self.class.const_source_location(:REACTIVE_FREIGHT_CARRIER).first,
192
- ),
193
- "#{self.class.to_s.split("::")[1].underscore}.yml",
194
- )
195
- @conf = YAML.safe_load_file(conf_path, permitted_classes: [Symbol])
196
-
197
- @rates_with_excessive_length_fees = @conf.dig(:attributes, :rates, :with_excessive_length_fees)
198
- end
322
+ return if tariff.blank?
323
+ raise ArgumentError, "#{name}#new: `tariff` must be a Tariff" unless tariff.is_a?(Tariff)
199
324
 
200
- # Asks the carrier for the scanned proof of delivery that the carrier would provide after delivery.
201
- #
202
- # @param [String] tracking_number Tracking number.
203
- # @return [DocumentResponse]
204
- def pod(tracking_number)
205
- raise NotImplementedError, "#{self.class.name}: #pod not supported"
325
+ @tariff = tariff
206
326
  end
207
327
 
208
328
  # Asks the carrier for the bill of lading that the carrier would provide before shipping.
@@ -211,46 +331,7 @@ module FreightKit
211
331
  #
212
332
  # @param [String] tracking_number Tracking number.
213
333
  # @return [DocumentResponse]
214
- def bol(tracking_number)
215
- raise NotImplementedError, "#{self.class.name}: #bol not supported"
216
- end
217
-
218
- # Asks the carrier for the scanned bill of lading that the carrier would provide after shipping.
219
- #
220
- # @see #bol
221
- #
222
- # @param [String] tracking_number Tracking number.
223
- # @return [DocumentResponse]
224
- def scanned_bol(tracking_number)
225
- raise NotImplementedError, "#{self.class.name}: #scanned_bol not supported"
226
- end
227
-
228
- def find_estimate(*)
229
- raise NotImplementedError, "#{self.class.name}: #find_estimate not supported"
230
- end
231
-
232
- # Asks the carrier for a list of locations (terminals) for a given country
233
- #
234
- # @param [ActiveUtils::Country] country
235
- # @return [Array<Location>]
236
- def find_locations(country)
237
- raise NotImplementedError, "#{self.class.name}: #find_locations not supported"
238
- end
239
-
240
- def find_tracking_number_from_pickup_number(pickup_number, date)
241
- raise NotImplementedError, "#{self.class.name}: #find_tracking_number_from_pickup_number not supported"
242
- end
243
-
244
- # Asks the carrier for rate estimates for a given shipment.
245
- #
246
- # @note Override with whatever you need to get the rates from the carrier.
247
- #
248
- # @param shipment [FreightKit::Shipment] Shipment details.
249
- # @return [FreightKit::RateResponse] The response from the carrier, which
250
- # includes 0 or more rate estimates for different shipping products
251
- def find_rates(shipment:)
252
- raise NotImplementedError, "#find_rates is not supported by #{self.class.name}."
253
- end
334
+ def bol(tracking_number) = raise NotImplementedError, "#{name}: #bol not supported"
254
335
 
255
336
  # Registers a new pickup with the carrier, to get a tracking number and
256
337
  # potentially shipping labels
@@ -283,19 +364,29 @@ module FreightKit
283
364
  service:,
284
365
  shipment:
285
366
  )
286
- raise NotImplementedError, "#create_pickup is not supported by #{self.class.name}."
367
+ raise NotImplementedError, "#create_pickup is not supported by #{name}."
287
368
  end
288
369
 
289
- # Cancels a shipment with a carrier.
370
+ # Fetch credential of given type.
290
371
  #
291
- # @note Override with whatever you need to cancel a shipping label
372
+ # @param type [Symbol] Type of credential to find, should be one of: `:api`, `:selenoid`, `:website`.
373
+ # @return [FreightKit::Credential|NilClass]
374
+ def fetch_credential(type) = credentials.find { |credential| credential.type == type }
375
+
376
+ # Asks the carrier for a list of locations (terminals) for a given country
292
377
  #
293
- # @param tracking_number [String] The tracking number of the shipment to cancel.
294
- # @return [FreightKit::Response] The response from the carrier. This
295
- # response in most cases has a cancellation id.
296
- def cancel_shipment(tracking_number)
297
- raise NotImplementedError, "#cancel_shipment is not supported by #{self.class.name}."
298
- end
378
+ # @param [ActiveUtils::Country] country
379
+ # @return [Array<Location>]
380
+ def find_locations(country) = raise NotImplementedError, "#{name}: #find_locations not supported"
381
+
382
+ # Asks the carrier for rate estimates for a given shipment.
383
+ #
384
+ # @note Override with whatever you need to get the rates from the carrier.
385
+ #
386
+ # @param shipment [FreightKit::Shipment] Shipment details.
387
+ # @return [FreightKit::RateResponse] The response from the carrier, which
388
+ # includes 0 or more rate estimates for different shipping products
389
+ def find_rates(shipment:) = raise NotImplementedError, "#find_rates is not supported by #{name}."
299
390
 
300
391
  # Retrieves tracking information for a previous shipment
301
392
  #
@@ -305,189 +396,44 @@ module FreightKit
305
396
  # @return [FreightKit::TrackingResponse] The response from the carrier. This
306
397
  # response should a list of shipment tracking events if successful.
307
398
  def find_tracking_info(tracking_number)
308
- raise NotImplementedError, "#find_tracking_info is not supported by #{self.class.name}."
399
+ raise NotImplementedError, "#find_tracking_info is not supported by #{name}."
309
400
  end
310
401
 
311
- # Get a list of services available for the a specific route.
312
- #
313
- # @param origin [Location] The origin location.
314
- # @param destination [Location] The destination location.
315
- # @return [Array<Symbol>] A list of service type symbols for the available services.
316
- #
317
- def available_services(origin, destination)
318
- raise NotImplementedError, "#available_services is not supported by #{self.class.name}."
402
+ def find_tracking_number_from_pickup_number(pickup_number, date)
403
+ raise NotImplementedError, "#{name}: #find_tracking_number_from_pickup_number not supported"
319
404
  end
320
405
 
321
- # Fetch credential of given type.
406
+ # Asks the carrier for the scanned proof of delivery that the carrier would provide after delivery.
322
407
  #
323
- # @param type [Symbol] Type of credential to find, should be one of: `:api`, `:selenoid`, `:website`.
324
- # @return [FreightKit::Credential|NilClass]
325
- def fetch_credential(type)
326
- @fetch_credentials ||= {}
327
- return @fetch_credentials[type] if @fetch_credentials[type].present?
328
-
329
- @fetch_credentials[type] ||= credentials.find { |credential| credential.type == type }
330
- end
408
+ # @param [String] tracking_number Tracking number.
409
+ # @return [DocumentResponse]
410
+ def pod(tracking_number) = raise NotImplementedError, "#{name}: #pod not supported"
331
411
 
332
- # Validate credentials with a call to the API.
412
+ # Asks the carrier for the scanned bill of lading that the carrier would provide after shipping.
333
413
  #
334
- # By default this just does a `find_rates` call with the origin and destination both as
335
- # the carrier's default_location. Override to provide alternate functionality.
414
+ # @see #bol
336
415
  #
337
- # @return [Boolean] Should return `true` if the provided credentials proved to work,
338
- # `false` otherswise.
339
- def valid_credentials?
340
- location = self.class.default_location
341
- find_rates(location, location, Package.new(100, [5, 15, 30]))
342
- rescue FreightKit::ResponseError
343
- false
344
- else
345
- true
346
- end
416
+ # @param [String] tracking_number Tracking number.
417
+ # @return [DocumentResponse]
418
+ def scanned_bol(tracking_number) = raise NotImplementedError, "#{name}: #scanned_bol not supported"
347
419
 
348
420
  # Validate the tracking number (may call API).
349
421
  #
350
422
  # @param [String] tracking_number Tracking number.
351
423
  # @return [Boolean] Should return `true` if the provided pro is valid.
352
424
  def valid_tracking_number?(tracking_number)
353
- raise NotImplementedError, "#valid_pro is not supported by #{self.class.name}."
354
- end
355
-
356
- # The package's longest horizontal dimension (length or width), as a
357
- # Measured::Length so comparisons stay unit-agnostic.
358
- #
359
- # @param package [FreightKit::Package]
360
- # @return [Measured::Length]
361
- def longest_dimension(package)
362
- [
363
- Measured::Length.new(package.length(:inches), :inches),
364
- Measured::Length.new(package.width(:inches), :inches),
365
- ].max
366
- end
367
-
368
- # @param package [FreightKit::Package]
369
- # @return [Boolean] whether the package is long enough to incur overlength fees.
370
- def overlength?(package) = longest_dimension(package) >= self.class.minimum_length_for_overlength_fees
371
-
372
- def overlength_fee(tariff, package)
373
- overlength_rule = overlength_rule_for(tariff, package)
374
- return 0 if overlength_rule.nil?
375
-
376
- package.quantity * overlength_rule.fee_cents
377
- end
378
-
379
- # Returns the overlength rule from +tariff+ that applies to +package+, or
380
- # +nil+ when the package is not overlength, or no configured rule covers it.
381
- #
382
- # This is the single source of truth for "does a rule cover this package?"
383
- # shared by {#overlength_fee} and {#validate_packages} so the two can never
384
- # disagree (e.g. a package quoting $0 overlength while also being treated as
385
- # serviceable).
386
- #
387
- # @param tariff [FreightKit::Tariff, nil]
388
- # @param package [FreightKit::Package]
389
- # @return [FreightKit::Tariff::OverlengthRule, nil]
390
- def overlength_rule_for(tariff, package)
391
- return unless tariff.is_a?(FreightKit::Tariff) && overlength?(package)
392
-
393
- tariff.overlength_rules.find { |overlength_rule| overlength_rule.cover?(longest_dimension(package)) }
394
- end
395
-
396
- # Determine whether the carrier will accept the packages based on credentials and/or tariff.
397
- # @param packages [Array<FreightKit::Package>]
398
- # @param tariff [FreightKit::Tariff]
399
- # @return [Boolean]
400
- def validate_packages(packages, tariff = nil)
401
- return false if packages.blank?
402
-
403
- message = []
404
-
405
- max_height_inches = self.class.maximum_height.convert_to(:inches).value
406
- if packages.map { |p| p.height(:inches) }.max > max_height_inches
407
- message << "items must be #{max_height_inches.to_f} inches tall or less"
408
- end
409
-
410
- max_weight_pounds = self.class.maximum_weight.convert_to(:pounds).value
411
- if packages.sum { |p| p.pounds(:total) } > max_weight_pounds
412
- message << "items must weigh #{max_weight_pounds.to_f} lbs or less"
413
- end
414
-
415
- # Carriers that don't quote overlength fees via their API rely on the
416
- # tariff to price them. Fail closed rather than silently under-quoting: a
417
- # missing, empty, or non-covering tariff for an overlength package must
418
- # make the carrier unserviceable. We key off rule *coverage* (via
419
- # #overlength_rule_for) rather than the tariff object's mere presence,
420
- # because a present-but-empty FreightKit::Tariff is not `blank?` and would
421
- # otherwise slip past this check.
422
- if self.class.overlength_fees_require_tariff?
423
- missing_dimensions = packages.any? do |package|
424
- [
425
- package.height(:inches),
426
- package.length(:inches),
427
- package.width(:inches),
428
- ].any?(&:zero?)
429
- end
430
-
431
- uncovered_overlength = packages.any? do |package|
432
- overlength?(package) && overlength_rule_for(tariff, package).nil?
433
- end
434
-
435
- if missing_dimensions
436
- message << 'item dimensions are required'
437
- elsif uncovered_overlength
438
- message << 'tariff must be defined to calculate overlength fees'
439
- end
440
- end
441
-
442
- raise UnserviceableError, message.join(', ').capitalize if message.present?
443
-
444
- true
445
- end
446
-
447
- def serviceable_accessorials?(accessorials)
448
- return true if accessorials.blank?
449
-
450
- unless self.class::REACTIVE_FREIGHT_CARRIER
451
- raise NotImplementedError, "#{self.class.name}: #serviceable_accessorials? not supported"
452
- end
453
-
454
- return false if @conf.dig(:accessorials, :mappable).blank?
455
-
456
- conf_mappable_accessorials = @conf.dig(:accessorials, :mappable)
457
- conf_unquotable_accessorials = @conf.dig(:accessorials, :unquotable)
458
- conf_unserviceable_accessorials = @conf.dig(:accessorials, :unserviceable)
459
-
460
- unserviceable_accessorials = []
461
-
462
- accessorials.each do |accessorial|
463
- if conf_unserviceable_accessorials.present? && conf_unserviceable_accessorials.any?(accessorial)
464
- unserviceable_accessorials << accessorial
465
- next
466
- end
467
-
468
- next if conf_mappable_accessorials.present? && conf_mappable_accessorials.keys.any?(accessorial)
469
- next if conf_unquotable_accessorials.present? && conf_unquotable_accessorials.any?(accessorial)
470
-
471
- unserviceable_accessorials << accessorial
472
- end
473
-
474
- if unserviceable_accessorials.present?
475
- raise FreightKit::UnserviceableAccessorialsError.new(accessorials: unserviceable_accessorials)
476
- end
477
-
478
- true
425
+ raise NotImplementedError, "#valid_tracking_number? is not supported by #{name}."
479
426
  end
480
427
 
481
428
  protected
482
429
 
483
- include ActiveUtils::RequiresParameters
484
- include ActiveUtils::PostsData
430
+ # Proxy for HTTP requests, from the optional `:api_proxy` credential.
431
+ # @return [String|NilClass]
432
+ def proxy_url = fetch_credential(:api_proxy)&.proxy_url
485
433
 
486
434
  # Use after building the request to save for later inspection.
487
435
  # @return [void]
488
- def save_request(request)
489
- @last_request = request
490
- end
436
+ def save_request(request) = @last_request = request
491
437
 
492
438
  # Calculates a timestamp that corresponds a given number of business days in the future
493
439
  #