freight_kit 0.1.20 → 0.1.21

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 (434) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +0 -2
  3. data/README.md +1 -2
  4. data/Rakefile +6 -0
  5. data/VERSION +1 -1
  6. data/configuration/locations/amazon_warehouses.yml +3330 -0
  7. data/freight_kit.gemspec +13 -13
  8. data/lib/freight_kit/address_normalizer.rb +26 -0
  9. data/lib/freight_kit/amazon_warehouse.rb +33 -0
  10. data/lib/freight_kit/api_clients/soap_client.rb +7 -9
  11. data/lib/freight_kit/carrier.rb +250 -303
  12. data/lib/freight_kit/carriers/a1_express.rb +25 -0
  13. data/lib/freight_kit/carriers/a_duie_pyle.rb +30 -0
  14. data/lib/freight_kit/carriers/aaa_cooper.rb +11 -0
  15. data/lib/freight_kit/carriers/aaa_expedited_services.rb +10 -0
  16. data/lib/freight_kit/carriers/ab_brothers_usa_inc.rb +12 -0
  17. data/lib/freight_kit/carriers/aberdeen_express_inc.rb +28 -0
  18. data/lib/freight_kit/carriers/abf_freight_system.rb +492 -0
  19. data/lib/freight_kit/carriers/access_transport.rb +10 -0
  20. data/lib/freight_kit/carriers/action_express.rb +10 -0
  21. data/lib/freight_kit/carriers/adams_and_companies.rb +10 -0
  22. data/lib/freight_kit/carriers/advance_distribution.rb +28 -0
  23. data/lib/freight_kit/carriers/alcon_transport.rb +10 -0
  24. data/lib/freight_kit/carriers/all_freight.rb +10 -0
  25. data/lib/freight_kit/carriers/alliance_transportation_group.rb +10 -0
  26. data/lib/freight_kit/carriers/allstate_transport.rb +10 -0
  27. data/lib/freight_kit/carriers/aloha_freight_forwarders.rb +35 -0
  28. data/lib/freight_kit/carriers/amado_trucking.rb +35 -0
  29. data/lib/freight_kit/carriers/american_fast_freight.rb +28 -0
  30. data/lib/freight_kit/carriers/amigos_service_transportation.rb +10 -0
  31. data/lib/freight_kit/carriers/anderson_towing_and_transport.rb +10 -0
  32. data/lib/freight_kit/carriers/apex_transporting.rb +10 -0
  33. data/lib/freight_kit/carriers/archer_cargo.rb +35 -0
  34. data/lib/freight_kit/carriers/armstrong_transport_group.rb +10 -0
  35. data/lib/freight_kit/carriers/autobahn_logistics.rb +10 -0
  36. data/lib/freight_kit/carriers/averitt_express.rb +30 -0
  37. data/lib/freight_kit/carriers/ba_transportation.rb +10 -0
  38. data/lib/freight_kit/carriers/balkin_express.rb +10 -0
  39. data/lib/freight_kit/carriers/bay_area_express.rb +10 -0
  40. data/lib/freight_kit/carriers/bc_freightways.rb +11 -0
  41. data/lib/freight_kit/carriers/benjamin_best_freight_inc.rb +37 -0
  42. data/lib/freight_kit/carriers/bennett_trucking.rb +10 -0
  43. data/lib/freight_kit/carriers/best_overnite_express.rb +78 -0
  44. data/lib/freight_kit/carriers/best_trucking.rb +10 -0
  45. data/lib/freight_kit/carriers/bestway_transport.rb +10 -0
  46. data/lib/freight_kit/carriers/bryan_systems.rb +10 -0
  47. data/lib/freight_kit/carriers/c_and_w_express.rb +10 -0
  48. data/lib/freight_kit/carriers/campbell_trucking.rb +10 -0
  49. data/lib/freight_kit/carriers/carde_transportation.rb +10 -0
  50. data/lib/freight_kit/carriers/cardinal_logistics.rb +28 -0
  51. data/lib/freight_kit/carriers/cdc_transport.rb +10 -0
  52. data/lib/freight_kit/carriers/cdo_express_diversified.rb +10 -0
  53. data/lib/freight_kit/carriers/cedar_supply_trucking.rb +10 -0
  54. data/lib/freight_kit/carriers/central_freight_lines.rb +12 -0
  55. data/lib/freight_kit/carriers/central_transport.rb +12 -0
  56. data/lib/freight_kit/carriers/chicago_suburban_express.rb +28 -0
  57. data/lib/freight_kit/carriers/city_logistics.rb +11 -0
  58. data/lib/freight_kit/carriers/clear_lane_freight_systems.rb +483 -0
  59. data/lib/freight_kit/carriers/cleopatra_trucking.rb +10 -0
  60. data/lib/freight_kit/carriers/clifford_transportation.rb +10 -0
  61. data/lib/freight_kit/carriers/cms_domestic.rb +25 -0
  62. data/lib/freight_kit/carriers/cnd_logistics.rb +10 -0
  63. data/lib/freight_kit/carriers/coast_to_coast_transport.rb +27 -0
  64. data/lib/freight_kit/carriers/countrywide_carriers.rb +10 -0
  65. data/lib/freight_kit/carriers/cpl_express.rb +35 -0
  66. data/lib/freight_kit/carriers/crosby_trucking_service.rb +29 -0
  67. data/lib/freight_kit/carriers/cross_country_freight_solutions.rb +419 -0
  68. data/lib/freight_kit/carriers/crowley.rb +10 -0
  69. data/lib/freight_kit/carriers/csa_transportation.rb +40 -0
  70. data/lib/freight_kit/carriers/csx_transportation.rb +40 -0
  71. data/lib/freight_kit/carriers/custom_global_logistics.rb +14 -0
  72. data/lib/freight_kit/carriers/d_and_a_transport.rb +10 -0
  73. data/lib/freight_kit/carriers/dak_transport.rb +10 -0
  74. data/lib/freight_kit/carriers/dash_courier_and_logistics_north_carolina.rb +10 -0
  75. data/lib/freight_kit/carriers/daylight_transport.rb +29 -0
  76. data/lib/freight_kit/carriers/dayton_freight_lines.rb +30 -0
  77. data/lib/freight_kit/carriers/dbr_logistics.rb +10 -0
  78. data/lib/freight_kit/carriers/deep_south_freight.rb +27 -0
  79. data/lib/freight_kit/carriers/delta_express.rb +10 -0
  80. data/lib/freight_kit/carriers/delta_transport.rb +10 -0
  81. data/lib/freight_kit/carriers/delta_trucking_logistics.rb +10 -0
  82. data/lib/freight_kit/carriers/demco_express.rb +10 -0
  83. data/lib/freight_kit/carriers/dependable_global_express.rb +10 -0
  84. data/lib/freight_kit/carriers/dependable_hawaiian_express.rb +24 -0
  85. data/lib/freight_kit/carriers/dependable_highway_express.rb +585 -0
  86. data/lib/freight_kit/carriers/desert_coastal_transport.rb +10 -0
  87. data/lib/freight_kit/carriers/dhl.rb +11 -0
  88. data/lib/freight_kit/carriers/diamond_line_delivery.rb +174 -0
  89. data/lib/freight_kit/carriers/ding_tai_trucking.rb +10 -0
  90. data/lib/freight_kit/carriers/diversified_transfer_and_storage.rb +29 -0
  91. data/lib/freight_kit/carriers/dohrn_transfer_company.rb +30 -0
  92. data/lib/freight_kit/carriers/dot_line_transportation.rb +29 -0
  93. data/lib/freight_kit/carriers/drt_transportation.rb +13 -0
  94. data/lib/freight_kit/carriers/dugan_truck_line.rb +29 -0
  95. data/lib/freight_kit/carriers/dupont.rb +10 -0
  96. data/lib/freight_kit/carriers/e_transport_carriers.rb +29 -0
  97. data/lib/freight_kit/carriers/echo_global_logistics.rb +13 -0
  98. data/lib/freight_kit/carriers/ecklund_logistics.rb +10 -0
  99. data/lib/freight_kit/carriers/el_emplumado_transport.rb +10 -0
  100. data/lib/freight_kit/carriers/elite_carriers.rb +28 -0
  101. data/lib/freight_kit/carriers/emerald_express.rb +10 -0
  102. data/lib/freight_kit/carriers/era_transport.rb +10 -0
  103. data/lib/freight_kit/carriers/estes_express_lines.rb +25 -0
  104. data/lib/freight_kit/carriers/euro_kam.rb +28 -0
  105. data/lib/freight_kit/carriers/ew_riverside_trucking.rb +10 -0
  106. data/lib/freight_kit/carriers/express_2000_inc.rb +12 -0
  107. data/lib/freight_kit/carriers/express_services_international.rb +10 -0
  108. data/lib/freight_kit/carriers/f_and_a_express.rb +27 -0
  109. data/lib/freight_kit/carriers/fairmont_logistics.rb +13 -0
  110. data/lib/freight_kit/carriers/fargo_cargo.rb +10 -0
  111. data/lib/freight_kit/carriers/fast_freight_transportation.rb +10 -0
  112. data/lib/freight_kit/carriers/fast_load_transport.rb +10 -0
  113. data/lib/freight_kit/carriers/fed_ex_express.rb +30 -0
  114. data/lib/freight_kit/carriers/fed_ex_ground.rb +24 -0
  115. data/lib/freight_kit/carriers/fed_ex_ltl_economy.rb +11 -0
  116. data/lib/freight_kit/carriers/fed_ex_ltl_priority.rb +11 -0
  117. data/lib/freight_kit/carriers/first_trucking_express.rb +10 -0
  118. data/lib/freight_kit/carriers/flash_trucking.rb +10 -0
  119. data/lib/freight_kit/carriers/fort_transportation_and_service_company_inc.rb +37 -0
  120. data/lib/freight_kit/carriers/forward_air.rb +789 -0
  121. data/lib/freight_kit/carriers/frahtex.rb +10 -0
  122. data/lib/freight_kit/carriers/frozen_food_express.rb +10 -0
  123. data/lib/freight_kit/carriers/gholia_bros_trucking.rb +36 -0
  124. data/lib/freight_kit/carriers/global_cargo.rb +10 -0
  125. data/lib/freight_kit/carriers/global_logistics_and_transportation.rb +10 -0
  126. data/lib/freight_kit/carriers/gls_freight.rb +32 -0
  127. data/lib/freight_kit/carriers/go_trucking_services.rb +10 -0
  128. data/lib/freight_kit/carriers/gold_eagle_transportation.rb +11 -0
  129. data/lib/freight_kit/carriers/golden_drop_trucking.rb +10 -0
  130. data/lib/freight_kit/carriers/gonzalez_transportation.rb +10 -0
  131. data/lib/freight_kit/carriers/gps_transport.rb +10 -0
  132. data/lib/freight_kit/carriers/greene_enterprise.rb +10 -0
  133. data/lib/freight_kit/carriers/gsa_international.rb +10 -0
  134. data/lib/freight_kit/carriers/gsp_express.rb +24 -0
  135. data/lib/freight_kit/carriers/gsv_transportation.rb +10 -0
  136. data/lib/freight_kit/carriers/gta_transportation.rb +10 -0
  137. data/lib/freight_kit/carriers/guam_freight_services.rb +10 -0
  138. data/lib/freight_kit/carriers/harrah_transportation.rb +23 -0
  139. data/lib/freight_kit/carriers/her_trucking.rb +10 -0
  140. data/lib/freight_kit/carriers/hercules_freight.rb +20 -0
  141. data/lib/freight_kit/carriers/highlander_xpress.rb +36 -0
  142. data/lib/freight_kit/carriers/hn_transport.rb +10 -0
  143. data/lib/freight_kit/carriers/honolulu_freight_service.rb +10 -0
  144. data/lib/freight_kit/carriers/hot_line_freight_system_inc.rb +12 -0
  145. data/lib/freight_kit/carriers/hotshot_freight_of_texas.rb +13 -0
  146. data/lib/freight_kit/carriers/houser_transport.rb +27 -0
  147. data/lib/freight_kit/carriers/infiniti_freight_logistics.rb +28 -0
  148. data/lib/freight_kit/carriers/infinity_trucking.rb +10 -0
  149. data/lib/freight_kit/carriers/interstate_tma.rb +10 -0
  150. data/lib/freight_kit/carriers/intrade_industries.rb +10 -0
  151. data/lib/freight_kit/carriers/jasper_trucking.rb +28 -0
  152. data/lib/freight_kit/carriers/jb_hunt.rb +11 -0
  153. data/lib/freight_kit/carriers/jfj_transportation.rb +8 -8
  154. data/lib/freight_kit/carriers/jkb_express.rb +10 -0
  155. data/lib/freight_kit/carriers/jlm_transport.rb +10 -0
  156. data/lib/freight_kit/carriers/johansson_transport.rb +10 -0
  157. data/lib/freight_kit/carriers/jones_express.rb +10 -0
  158. data/lib/freight_kit/carriers/jp_logistics.rb +41 -0
  159. data/lib/freight_kit/carriers/just_in_time_cargo.rb +29 -0
  160. data/lib/freight_kit/carriers/kengkok_times.rb +10 -0
  161. data/lib/freight_kit/carriers/kings_express.rb +10 -0
  162. data/lib/freight_kit/carriers/klc_transportation.rb +10 -0
  163. data/lib/freight_kit/carriers/km_trucking.rb +10 -0
  164. data/lib/freight_kit/carriers/kma_logistics.rb +10 -0
  165. data/lib/freight_kit/carriers/krc_logistics.rb +10 -0
  166. data/lib/freight_kit/carriers/ktx.rb +10 -0
  167. data/lib/freight_kit/carriers/landstar.rb +25 -0
  168. data/lib/freight_kit/carriers/lanter_distributing_llc.rb +30 -0
  169. data/lib/freight_kit/carriers/ld_trucking.rb +10 -0
  170. data/lib/freight_kit/carriers/legacy_logistics_solutions.rb +10 -0
  171. data/lib/freight_kit/carriers/leonards_express.rb +10 -0
  172. data/lib/freight_kit/carriers/liberty_linehaul_west.rb +28 -0
  173. data/lib/freight_kit/carriers/liberty_transport.rb +10 -0
  174. data/lib/freight_kit/carriers/lightning_express.rb +10 -0
  175. data/lib/freight_kit/carriers/lj_express.rb +24 -0
  176. data/lib/freight_kit/carriers/lkp_enterprises.rb +10 -0
  177. data/lib/freight_kit/carriers/ltl_pros.rb +28 -0
  178. data/lib/freight_kit/carriers/m_and_m_and_sons.rb +10 -0
  179. data/lib/freight_kit/carriers/mag_lines_transport.rb +10 -0
  180. data/lib/freight_kit/carriers/magic_messenger.rb +24 -0
  181. data/lib/freight_kit/carriers/majors_transit.rb +10 -0
  182. data/lib/freight_kit/carriers/map_global_logistics.rb +10 -0
  183. data/lib/freight_kit/carriers/matths_trucking.rb +11 -0
  184. data/lib/freight_kit/carriers/mav_canadian_transport.rb +13 -0
  185. data/lib/freight_kit/carriers/mc_systems.rb +35 -0
  186. data/lib/freight_kit/carriers/mega_fleet.rb +10 -0
  187. data/lib/freight_kit/carriers/mega_trans_group.rb +28 -0
  188. data/lib/freight_kit/carriers/meta_express.rb +10 -0
  189. data/lib/freight_kit/carriers/mia_transportation.rb +10 -0
  190. data/lib/freight_kit/carriers/midwest_motor_express.rb +14 -0
  191. data/lib/freight_kit/carriers/midwest_transport_and_trucking.rb +10 -0
  192. data/lib/freight_kit/carriers/mikade_delivery_service.rb +10 -0
  193. data/lib/freight_kit/carriers/mohoff_freight_lines.rb +23 -0
  194. data/lib/freight_kit/carriers/montata_travelers_express.rb +10 -0
  195. data/lib/freight_kit/carriers/morgan_van_lines.rb +29 -0
  196. data/lib/freight_kit/carriers/moto_transportation.rb +24 -0
  197. data/lib/freight_kit/carriers/mountain_valley_express.rb +197 -0
  198. data/lib/freight_kit/carriers/ms_freight.rb +27 -0
  199. data/lib/freight_kit/carriers/mvg_transport.rb +10 -0
  200. data/lib/freight_kit/carriers/n_and_m_transfer_co_inc.rb +29 -0
  201. data/lib/freight_kit/carriers/nabot_transport_solutions.rb +10 -0
  202. data/lib/freight_kit/carriers/national_freight_xpress.rb +10 -0
  203. data/lib/freight_kit/carriers/navigation_group.rb +10 -0
  204. data/lib/freight_kit/carriers/nelson_trucking.rb +10 -0
  205. data/lib/freight_kit/carriers/network_1_transportation.rb +10 -0
  206. data/lib/freight_kit/carriers/new_century_transport.rb +28 -0
  207. data/lib/freight_kit/carriers/new_penn_motor_express.rb +11 -0
  208. data/lib/freight_kit/carriers/nieves_transportation.rb +10 -0
  209. data/lib/freight_kit/carriers/nolan_transportation_group.rb +26 -0
  210. data/lib/freight_kit/carriers/northland_trucking.rb +10 -0
  211. data/lib/freight_kit/carriers/northwest_carrier_logistics.rb +27 -0
  212. data/lib/freight_kit/carriers/nt_usa.rb +10 -0
  213. data/lib/freight_kit/carriers/nu_line_transportation.rb +10 -0
  214. data/lib/freight_kit/carriers/numark_transportation.rb +80 -0
  215. data/lib/freight_kit/carriers/nvk_transport.rb +10 -0
  216. data/lib/freight_kit/carriers/ny_transport.rb +10 -0
  217. data/lib/freight_kit/carriers/oak_harbor.rb +28 -0
  218. data/lib/freight_kit/carriers/oakline_transportation.rb +10 -0
  219. data/lib/freight_kit/carriers/old_dominion_freight_line.rb +30 -0
  220. data/lib/freight_kit/carriers/on_trac.rb +573 -0
  221. data/lib/freight_kit/carriers/one_hundred_one_transport.rb +10 -0
  222. data/lib/freight_kit/carriers/one_way_delivery.rb +10 -0
  223. data/lib/freight_kit/carriers/oracle_transportation_solutions.rb +10 -0
  224. data/lib/freight_kit/carriers/orange_courier.rb +27 -0
  225. data/lib/freight_kit/carriers/ortas_trucking.rb +10 -0
  226. data/lib/freight_kit/carriers/pac_trux_transportation.rb +10 -0
  227. data/lib/freight_kit/carriers/pacer.rb +10 -0
  228. data/lib/freight_kit/carriers/pacific_logistics.rb +10 -0
  229. data/lib/freight_kit/carriers/pacific_states_truck_lines.rb +10 -0
  230. data/lib/freight_kit/carriers/paradise_distributing.rb +10 -0
  231. data/lib/freight_kit/carriers/paramount_freight_systems.rb +10 -0
  232. data/lib/freight_kit/carriers/peninsula_truck_lines.rb +222 -0
  233. data/lib/freight_kit/carriers/pg_transport.rb +10 -0
  234. data/lib/freight_kit/carriers/pgs_360.rb +10 -0
  235. data/lib/freight_kit/carriers/pilot_freight_services.rb +10 -0
  236. data/lib/freight_kit/carriers/pious_trans.rb +27 -0
  237. data/lib/freight_kit/carriers/pitt_ohio_express.rb +30 -0
  238. data/lib/freight_kit/carriers/pki_logistics.rb +12 -0
  239. data/lib/freight_kit/carriers/plana_transportation.rb +28 -0
  240. data/lib/freight_kit/carriers/prestige.rb +10 -0
  241. data/lib/freight_kit/carriers/pro_trans_solutions.rb +28 -0
  242. data/lib/freight_kit/carriers/puma_logistics.rb +10 -0
  243. data/lib/freight_kit/carriers/pwc_international.rb +10 -0
  244. data/lib/freight_kit/carriers/quality_logistics.rb +10 -0
  245. data/lib/freight_kit/carriers/queen_star_trucking.rb +27 -0
  246. data/lib/freight_kit/carriers/r_and_l_carriers.rb +11 -0
  247. data/lib/freight_kit/carriers/rac_transport.rb +10 -0
  248. data/lib/freight_kit/carriers/re_logistics.rb +23 -0
  249. data/lib/freight_kit/carriers/reddaway.rb +11 -0
  250. data/lib/freight_kit/carriers/reefer_van_network.rb +13 -0
  251. data/lib/freight_kit/carriers/refrigerated_trucking_and_ltl_transportation_services.rb +10 -0
  252. data/lib/freight_kit/carriers/ridgeline_express.rb +10 -0
  253. data/lib/freight_kit/carriers/rist_transport.rb +29 -0
  254. data/lib/freight_kit/carriers/river_city_transport.rb +10 -0
  255. data/lib/freight_kit/carriers/roadrunner_transportation_services.rb +675 -0
  256. data/lib/freight_kit/carriers/roadtex.rb +13 -0
  257. data/lib/freight_kit/carriers/ronald_transport_services.rb +10 -0
  258. data/lib/freight_kit/carriers/rose_trucking.rb +24 -0
  259. data/lib/freight_kit/carriers/rp_and_j_transport.rb +24 -0
  260. data/lib/freight_kit/carriers/rpm_transportation.rb +11 -0
  261. data/lib/freight_kit/carriers/rude_transportation.rb +30 -0
  262. data/lib/freight_kit/carriers/s_and_s_logistics.rb +10 -0
  263. data/lib/freight_kit/carriers/saia.rb +470 -361
  264. data/lib/freight_kit/carriers/sb_transportation.rb +27 -0
  265. data/lib/freight_kit/carriers/schneider_national.rb +29 -0
  266. data/lib/freight_kit/carriers/schwarz_trucking.rb +10 -0
  267. data/lib/freight_kit/carriers/sewell_motor_express.rb +29 -0
  268. data/lib/freight_kit/carriers/shawnee_trucking.rb +28 -0
  269. data/lib/freight_kit/carriers/shi_logistics.rb +10 -0
  270. data/lib/freight_kit/carriers/sinbad_transport.rb +10 -0
  271. data/lib/freight_kit/carriers/skyway.rb +10 -0
  272. data/lib/freight_kit/carriers/smith_cargo_transportation_services.rb +23 -0
  273. data/lib/freight_kit/carriers/sna_transportation.rb +10 -0
  274. data/lib/freight_kit/carriers/solid_group.rb +10 -0
  275. data/lib/freight_kit/carriers/solution_carrier_express.rb +10 -0
  276. data/lib/freight_kit/carriers/southeastern_freight_lines.rb +450 -0
  277. data/lib/freight_kit/carriers/southwestern_motor_transport.rb +30 -0
  278. data/lib/freight_kit/carriers/span_alaska.rb +10 -0
  279. data/lib/freight_kit/carriers/specialize_transportation.rb +27 -0
  280. data/lib/freight_kit/carriers/ssi_refrigerated_express.rb +10 -0
  281. data/lib/freight_kit/carriers/standard_forwarding_llc.rb +28 -0
  282. data/lib/freight_kit/carriers/star_american_enterprise.rb +10 -0
  283. data/lib/freight_kit/carriers/sterling_transportation.rb +10 -0
  284. data/lib/freight_kit/carriers/stg.rb +163 -0
  285. data/lib/freight_kit/carriers/supervan_service.rb +10 -0
  286. data/lib/freight_kit/carriers/sutton_transport_inc.rb +12 -0
  287. data/lib/freight_kit/carriers/swift_transportation.rb +28 -0
  288. data/lib/freight_kit/carriers/t_force_worldwide.rb +617 -0
  289. data/lib/freight_kit/carriers/tax_airfreight_inc.rb +35 -0
  290. data/lib/freight_kit/carriers/tforce_freight_inc.rb +30 -0
  291. data/lib/freight_kit/carriers/the_custom_companies.rb +162 -0
  292. data/lib/freight_kit/carriers/thk_trucking.rb +28 -0
  293. data/lib/freight_kit/carriers/tiger_cool_express.rb +11 -0
  294. data/lib/freight_kit/carriers/tili_logistics.rb +10 -0
  295. data/lib/freight_kit/carriers/tmt_industries.rb +10 -0
  296. data/lib/freight_kit/carriers/top_ten_express.rb +28 -0
  297. data/lib/freight_kit/carriers/total_quality_logistics.rb +338 -0
  298. data/lib/freight_kit/carriers/total_transportation.rb +258 -0
  299. data/lib/freight_kit/carriers/trans_international_trucking.rb +29 -0
  300. data/lib/freight_kit/carriers/treasure_transportation.rb +10 -0
  301. data/lib/freight_kit/carriers/tri_state_services.rb +10 -0
  302. data/lib/freight_kit/carriers/tritex_freighters.rb +10 -0
  303. data/lib/freight_kit/carriers/triways.rb +10 -0
  304. data/lib/freight_kit/carriers/tsi_kansas.rb +29 -0
  305. data/lib/freight_kit/carriers/u_and_r_transportation.rb +23 -0
  306. data/lib/freight_kit/carriers/union_pacific.rb +11 -0
  307. data/lib/freight_kit/carriers/united_freight_logistics.rb +10 -0
  308. data/lib/freight_kit/carriers/unlimited_distance_transportation.rb +10 -0
  309. data/lib/freight_kit/carriers/up_streamline.rb +10 -0
  310. data/lib/freight_kit/carriers/ups_freight.rb +12 -0
  311. data/lib/freight_kit/carriers/us_freightways.rb +10 -0
  312. data/lib/freight_kit/carriers/usa_truck.rb +28 -0
  313. data/lib/freight_kit/carriers/usf_holland.rb +11 -0
  314. data/lib/freight_kit/carriers/valley_cartage.rb +11 -0
  315. data/lib/freight_kit/carriers/vc_transport.rb +10 -0
  316. data/lib/freight_kit/carriers/vision_express.rb +11 -0
  317. data/lib/freight_kit/carriers/vision_logistics_group.rb +10 -0
  318. data/lib/freight_kit/carriers/vmg_transportation_group.rb +10 -0
  319. data/lib/freight_kit/carriers/volpe_express.rb +10 -0
  320. data/lib/freight_kit/carriers/ward_trucking.rb +29 -0
  321. data/lib/freight_kit/carriers/wdwb.rb +10 -0
  322. data/lib/freight_kit/carriers/western_flyer_express.rb +28 -0
  323. data/lib/freight_kit/carriers/western_regional_delivery_service.rb +271 -0
  324. data/lib/freight_kit/carriers/western_specialized_trucking.rb +22 -0
  325. data/lib/freight_kit/carriers/win_distribution.rb +28 -0
  326. data/lib/freight_kit/carriers/wlb_transport.rb +10 -0
  327. data/lib/freight_kit/carriers/x_trux.rb +29 -0
  328. data/lib/freight_kit/carriers/xpo_logistics.rb +427 -0
  329. data/lib/freight_kit/carriers/xpress_global_systems.rb +30 -0
  330. data/lib/freight_kit/carriers/xylo_trucking.rb +10 -0
  331. data/lib/freight_kit/carriers/yrc_freight.rb +24 -0
  332. data/lib/freight_kit/carriers/zentner_transportation.rb +28 -0
  333. data/lib/freight_kit/carriers.rb +331 -34
  334. data/lib/freight_kit/countries.rb +22 -0
  335. data/lib/freight_kit/error.rb +0 -2
  336. data/lib/freight_kit/errors/document_not_found_error.rb +0 -2
  337. data/lib/freight_kit/errors/expired_credentials_error.rb +0 -2
  338. data/lib/freight_kit/errors/http_error.rb +0 -2
  339. data/lib/freight_kit/errors/invalid_credentials_error.rb +0 -2
  340. data/lib/freight_kit/errors/response_error.rb +0 -2
  341. data/lib/freight_kit/errors/shipment_not_found_error.rb +0 -2
  342. data/lib/freight_kit/errors/unserviceable_accessorials_error.rb +2 -4
  343. data/lib/freight_kit/errors/unserviceable_error.rb +0 -2
  344. data/lib/freight_kit/helpers/documentable.rb +0 -2
  345. data/lib/freight_kit/helpers/pickupable.rb +3 -5
  346. data/lib/freight_kit/helpers/rateable.rb +0 -2
  347. data/lib/freight_kit/helpers/trackable.rb +0 -2
  348. data/lib/freight_kit/http_client/cache_store.rb +2 -4
  349. data/lib/freight_kit/http_client/log_device.rb +0 -2
  350. data/lib/freight_kit/http_client/response.rb +0 -2
  351. data/lib/freight_kit/http_client/revalidation.rb +0 -2
  352. data/lib/freight_kit/http_client/safe_retries.rb +0 -2
  353. data/lib/freight_kit/http_client/zstd.rb +2 -4
  354. data/lib/freight_kit/http_client.rb +8 -12
  355. data/lib/freight_kit/model.rb +1 -3
  356. data/lib/freight_kit/models/address.rb +15 -0
  357. data/lib/freight_kit/models/contact.rb +3 -4
  358. data/lib/freight_kit/models/country.rb +20 -0
  359. data/lib/freight_kit/models/credential.rb +14 -16
  360. data/lib/freight_kit/models/date_time.rb +0 -2
  361. data/lib/freight_kit/models/document_response.rb +0 -2
  362. data/lib/freight_kit/models/label.rb +0 -2
  363. data/lib/freight_kit/models/location.rb +10 -25
  364. data/lib/freight_kit/models/pickup_response.rb +0 -2
  365. data/lib/freight_kit/models/price.rb +0 -2
  366. data/lib/freight_kit/models/rate.rb +0 -2
  367. data/lib/freight_kit/models/rate_response.rb +0 -2
  368. data/lib/freight_kit/models/region.rb +19 -0
  369. data/lib/freight_kit/models/response.rb +0 -2
  370. data/lib/freight_kit/models/shipment.rb +4 -6
  371. data/lib/freight_kit/models/shipment_event.rb +0 -2
  372. data/lib/freight_kit/models/terminal.rb +10 -0
  373. data/lib/freight_kit/models/tracking_response.rb +0 -2
  374. data/lib/freight_kit/package.rb +51 -53
  375. data/lib/freight_kit/package_item.rb +14 -14
  376. data/lib/freight_kit/packaging.rb +21 -26
  377. data/lib/freight_kit/platform.rb +0 -32
  378. data/lib/freight_kit/platforms/carrier_logistics.rb +331 -345
  379. data/lib/freight_kit/platforms/next_tms.rb +93 -0
  380. data/lib/freight_kit/platforms/the_great_information_factory.rb +500 -425
  381. data/lib/freight_kit/regions.rb +27 -0
  382. data/lib/freight_kit/shipment_packer.rb +36 -38
  383. data/lib/freight_kit/tariff/overlength_rule.rb +1 -5
  384. data/lib/freight_kit/tariff.rb +0 -2
  385. data/lib/freight_kit.rb +84 -11
  386. metadata +361 -51
  387. data/configuration/carriers/abfs.yml +0 -124
  388. data/configuration/carriers/btvp.yml +0 -84
  389. data/configuration/carriers/ccyq.yml +0 -121
  390. data/configuration/carriers/clni.yml +0 -113
  391. data/configuration/carriers/cnwy.yml +0 -113
  392. data/configuration/carriers/ctbv.yml +0 -117
  393. data/configuration/carriers/dcha.yml +0 -105
  394. data/configuration/carriers/dlds.yml +0 -111
  395. data/configuration/carriers/dphe.yml +0 -130
  396. data/configuration/carriers/drrq.yml +0 -131
  397. data/configuration/carriers/fcsy.yml +0 -102
  398. data/configuration/carriers/fwda.yml +0 -137
  399. data/configuration/carriers/jfj_transportation.yml +0 -2
  400. data/configuration/carriers/mtvl.yml +0 -12
  401. data/configuration/carriers/numk.yml +0 -14
  402. data/configuration/carriers/otcl.yml +0 -124
  403. data/configuration/carriers/pens.yml +0 -22
  404. data/configuration/carriers/rdfs.yml +0 -142
  405. data/configuration/carriers/saia.yml +0 -129
  406. data/configuration/carriers/sefl.yml +0 -115
  407. data/configuration/carriers/totl.yml +0 -111
  408. data/configuration/carriers/tqyl.yml +0 -28
  409. data/configuration/carriers/wrds.yml +0 -20
  410. data/configuration/platforms/carrier_logistics.yml +0 -25
  411. data/configuration/platforms/next.yml +0 -12
  412. data/configuration/platforms/the_great_information_factory.yml +0 -122
  413. data/lib/freight_kit/carriers/abfs.rb +0 -421
  414. data/lib/freight_kit/carriers/btvp.rb +0 -29
  415. data/lib/freight_kit/carriers/ccyq.rb +0 -310
  416. data/lib/freight_kit/carriers/clni.rb +0 -396
  417. data/lib/freight_kit/carriers/cnwy.rb +0 -327
  418. data/lib/freight_kit/carriers/ctbv.rb +0 -53
  419. data/lib/freight_kit/carriers/dcha.rb +0 -76
  420. data/lib/freight_kit/carriers/dlds.rb +0 -49
  421. data/lib/freight_kit/carriers/dphe.rb +0 -472
  422. data/lib/freight_kit/carriers/drrq.rb +0 -580
  423. data/lib/freight_kit/carriers/fcsy.rb +0 -57
  424. data/lib/freight_kit/carriers/fwda.rb +0 -744
  425. data/lib/freight_kit/carriers/mtvl.rb +0 -34
  426. data/lib/freight_kit/carriers/numk.rb +0 -58
  427. data/lib/freight_kit/carriers/otcl.rb +0 -520
  428. data/lib/freight_kit/carriers/pens.rb +0 -204
  429. data/lib/freight_kit/carriers/rdfs.rb +0 -521
  430. data/lib/freight_kit/carriers/sefl.rb +0 -342
  431. data/lib/freight_kit/carriers/totl.rb +0 -172
  432. data/lib/freight_kit/carriers/tqyl.rb +0 -337
  433. data/lib/freight_kit/carriers/wrds.rb +0 -246
  434. 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,114 @@ 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
+ [
76
+ Measured::Length.new(package.length(:inches), :inches),
77
+ Measured::Length.new(package.width(:inches), :inches)
78
+ ].max
58
79
  end
59
80
 
81
+ # FreightKit accessorials the carrier prices, mapped to the carrier's codes.
82
+ # @return [Hash{Symbol => Object}]
83
+ def mappable_accessorials = {}
84
+
60
85
  # The maximum height the carrier will accept.
61
86
  # @return [Measured::Length]
62
- def maximum_height
63
- Measured::Length.new(105, :inches)
64
- end
87
+ def maximum_height = Measured::Length.new(105, :inches)
65
88
 
66
89
  # The maximum weight the carrier will accept.
67
90
  # @return [Measured::Weight]
68
- def maximum_weight
69
- Measured::Weight.new(10_000, :pounds)
70
- end
91
+ def maximum_weight = Measured::Weight.new(10_000, :pounds)
71
92
 
72
93
  # What length overlength fees the carrier begins charging at.
73
94
  # @return [Measured::Length]
74
- def minimum_length_for_overlength_fees
75
- Measured::Length.new(48, :inches)
95
+ def minimum_length_for_overlength_fees = Measured::Length.new(48, :inches)
96
+
97
+ # @param package [FreightKit::Package]
98
+ # @return [Boolean] whether the package is long enough to incur overlength fees.
99
+ def overlength?(package) = longest_dimension(package) >= minimum_length_for_overlength_fees
100
+
101
+ def overlength_fee(tariff, package)
102
+ overlength_rule = overlength_rule_for(tariff, package)
103
+ return 0 if overlength_rule.nil?
104
+
105
+ package.quantity * overlength_rule.fee_cents
76
106
  end
77
107
 
78
108
  # Whether or not the carrier quotes overlength fees via API.
79
109
  # @note Should the API not calculate these fees, they should be calculated some other way outside of FreightKit.
80
110
  # @return [Boolean]
81
- def overlength_fees_require_tariff?
82
- true
111
+ def overlength_fees_require_tariff? = true
112
+
113
+ # Returns the overlength rule from +tariff+ that applies to +package+, or
114
+ # +nil+ when the package is not overlength, or no configured rule covers it.
115
+ #
116
+ # This is the single source of truth for "does a rule cover this package?"
117
+ # shared by {#overlength_fee} and {#validate_packages} so the two can never
118
+ # disagree (e.g. a package quoting $0 overlength while also being treated as
119
+ # serviceable).
120
+ #
121
+ # @param tariff [FreightKit::Tariff, nil]
122
+ # @param package [FreightKit::Package]
123
+ # @return [FreightKit::Tariff::OverlengthRule, nil]
124
+ def overlength_rule_for(tariff, package)
125
+ return unless tariff.is_a?(FreightKit::Tariff) && overlength?(package)
126
+
127
+ tariff.overlength_rules.find { |overlength_rule| overlength_rule.cover?(longest_dimension(package)) }
83
128
  end
84
129
 
85
130
  # Whether carrier considers pickup number the same as the tracking number.
86
- def pickup_number_is_tracking_number?
87
- false
88
- end
131
+ def pickup_number_is_tracking_number? = false
132
+
133
+ # Whether the rates the carrier's API returns include excessive length fees. Carriers without rates, or that need
134
+ # a tariff to price overlength fees, return rates without them.
135
+ # @return [Boolean]
136
+ def rates_with_excessive_length_fees? = find_rates_implemented? && requirements.exclude?(:tariff)
137
+
138
+ # Returns the `Credential` methods (passed to `#initialize`) that cannot respond with blank values.
139
+ # @return [Array<Symbol>]
140
+ def required_credential_types = []
89
141
 
90
142
  # Returns the keywords passed to `#initialize` that cannot be blank.
91
143
  # @return [Array<Symbol>]
92
- def requirements
93
- []
144
+ def requirements = []
145
+
146
+ # @return [String, nil]
147
+ def scac = nil
148
+
149
+ # Raises {UnserviceableAccessorialsError} for accessorials the carrier refuses, or that it neither maps nor serves
150
+ # unpriced. Returns false when the carrier maps no accessorials.
151
+ # @return [Boolean]
152
+ def serviceable_accessorials?(accessorials)
153
+ return true if accessorials.blank?
154
+ return false if mappable_accessorials.blank?
155
+
156
+ refused = accessorials.select do |accessorial|
157
+ unserviceable_accessorials.include?(accessorial) ||
158
+ (mappable_accessorials.keys.exclude?(accessorial) && unquotable_accessorials.exclude?(accessorial))
159
+ end
160
+ raise FreightKit::UnserviceableAccessorialsError.new(accessorials: refused) if refused.any?
161
+
162
+ true
94
163
  end
95
164
 
96
- # Returns the `Credential` methods (passed to `#initialize`) that cannot respond with blank values.
165
+ # The services {#find_rates} quotes (e.g. `:standard`, `:guaranteed_delivery`).
97
166
  # @return [Array<Symbol>]
98
- def required_credential_types
99
- %i[api]
100
- end
167
+ def services = []
168
+
169
+ # The carrier's terminals, so applications need not enter them for each customer.
170
+ # @return [Array<FreightKit::Terminal>]
171
+ def terminals = []
101
172
 
102
173
  # The template URL for tracking one of carrier's `NUMBERS` publicly. A template URL is a URL containing the token
103
174
  # "%s" that can be replaced to generate a valid URL.
@@ -112,11 +183,29 @@ module FreightKit
112
183
  # @raise [ArgumentError]
113
184
  # @return [String, nil] The template URL or nil if no template is available for the given key.
114
185
  def tracking_url_template(key)
115
- raise ArgumentError, "key must be one of: #{NUMBERS.join(", ")}" if NUMBERS.exclude?(key)
186
+ raise ArgumentError, "key must be one of: #{NUMBERS.join(', ')}" if NUMBERS.exclude?(key)
116
187
 
117
- "#{self}::#{key.to_s.upcase}_TRACKING_URL_TEMPLATE".constantize
188
+ tracking_url_templates[key]
118
189
  end
119
190
 
191
+ # The template URLs for {.tracking_url_template}, by `NUMBERS` key.
192
+ # @return [Hash{Symbol => String}]
193
+ def tracking_url_templates = {}
194
+
195
+ # FreightKit accessorials the carrier serves but does not price.
196
+ # @return [Array<Symbol>]
197
+ def unquotable_accessorials = []
198
+
199
+ # FreightKit accessorials the carrier refuses.
200
+ # @return [Array<Symbol>]
201
+ def unserviceable_accessorials = []
202
+
203
+ # @return [Integer, nil]
204
+ def us_dot_number = nil
205
+
206
+ # @return [Integer, nil]
207
+ def us_mc_number = nil
208
+
120
209
  # Regular expression to use for validating carrier's `NUMBERS`.
121
210
  #
122
211
  # Returns the regular expression used for validating the carrier's number based on the provided `key`.
@@ -125,30 +214,87 @@ module FreightKit
125
214
  # @see `NUMBERS`
126
215
  # @param [Symbol] key The symbol representing the carrier number type for which the regular expression is needed.
127
216
  # @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.
217
+ # @return [Regexp, nil] The regular expression for validating the specified carrier number type.
129
218
  def valid_number_regex(key)
130
- raise ArgumentError, "key must be one of: #{NUMBERS.join(", ")}" if NUMBERS.exclude?(key)
219
+ raise ArgumentError, "key must be one of: #{NUMBERS.join(', ')}" if NUMBERS.exclude?(key)
131
220
 
132
- "#{self}::VALID_#{key.to_s.upcase}_REGEX".constantize
221
+ valid_number_regexes[key]
133
222
  end
134
- end
135
223
 
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
224
+ # The regular expressions for {.valid_number_regex}, by `NUMBERS` key.
225
+ # @return [Hash{Symbol => Regexp}]
226
+ def valid_number_regexes = {}
227
+
228
+ # Determine whether the carrier will accept the packages based on credentials and/or tariff.
229
+ # @param packages [Array<FreightKit::Package>]
230
+ # @param tariff [FreightKit::Tariff]
231
+ # @return [Boolean]
232
+ def validate_packages(packages, tariff = nil)
233
+ return false if packages.blank?
234
+
235
+ message = []
236
+
237
+ max_height_inches = maximum_height.convert_to(:inches).value
238
+ if packages.map { |p| p.height(:inches) }.max > max_height_inches
239
+ message << "items must be #{max_height_inches.to_f} inches tall or less"
240
+ end
241
+
242
+ max_weight_pounds = maximum_weight.convert_to(:pounds).value
243
+ message << "items must weigh #{max_weight_pounds.to_f} lbs or less" if packages.sum { |p| p.pounds(:total) } > max_weight_pounds
244
+
245
+ # Carriers that don't quote overlength fees via their API rely on the
246
+ # tariff to price them. Fail closed rather than silently under-quoting: a
247
+ # missing, empty, or non-covering tariff for an overlength package must
248
+ # make the carrier unserviceable. We key off rule *coverage* (via
249
+ # #overlength_rule_for) rather than the tariff object's mere presence,
250
+ # because a present-but-empty FreightKit::Tariff is not `blank?` and would
251
+ # otherwise slip past this check.
252
+ if overlength_fees_require_tariff?
253
+ missing_dimensions = packages.any? do |package|
254
+ [package.height(:inches), package.length(:inches), package.width(:inches)].any?(&:zero?)
255
+ end
256
+
257
+ uncovered_overlength = packages.any? do |package|
258
+ overlength?(package) && overlength_rule_for(tariff, package).nil?
259
+ end
260
+
261
+ if missing_dimensions
262
+ message << 'item dimensions are required'
263
+ elsif uncovered_overlength
264
+ message << 'tariff must be defined to calculate overlength fees'
265
+ end
266
+ end
267
+
268
+ raise UnserviceableError, message.join(', ').capitalize if message.present?
269
+
270
+ true
271
+ end
272
+
273
+ # The carrier's homepage, verified to load over HTTPS and to name the carrier (e.g. "https://abf.com").
274
+ # @return [String, nil]
275
+ def website_url = nil
276
+ end
146
277
 
147
- NUMBERS = %i[bol_number order_number pickup_number po_number tracking_number]
278
+ NUMBERS = %i[bol_number order_number pickup_number po_number tracking_number].freeze
148
279
 
149
- attr_accessor :conf, :rates_with_excessive_length_fees, :tmpdir
150
280
  attr_reader :credentials, :customer_location, :last_request, :tariff
151
281
 
282
+ delegate :id,
283
+ :longest_dimension,
284
+ :mappable_accessorials,
285
+ :name,
286
+ :overlength?,
287
+ :overlength_fee,
288
+ :overlength_rule_for,
289
+ :rates_with_excessive_length_fees?,
290
+ :scac,
291
+ :serviceable_accessorials?,
292
+ :unquotable_accessorials,
293
+ :unserviceable_accessorials,
294
+ :valid_number_regex,
295
+ :validate_packages,
296
+ to: :class
297
+
152
298
  # @param credentials [Array<Credential>]
153
299
  # @param customer_location [Location]
154
300
  # @param tariff [Tariff]
@@ -156,14 +302,14 @@ module FreightKit
156
302
  credentials = [credentials] if credentials.is_a?(Credential)
157
303
 
158
304
  if credentials.map(&:class).uniq != [Credential]
159
- message = "#{self.class.name}#new: `credentials` must be a Credential or Array of Credential"
305
+ message = "#{name}#new: `credentials` must be a Credential or Array of Credential"
160
306
  raise ArgumentError, message
161
307
  end
162
308
 
163
309
  missing_credential_types = self.class.required_credential_types.uniq - credentials.map(&:type).uniq
164
310
 
165
311
  if missing_credential_types.any?
166
- message = "#{self.class.name}#new: `Credential` of type(s) missing: #{missing_credential_types.join(", ")}"
312
+ message = "#{name}#new: `Credential` of type(s) missing: #{missing_credential_types.join(', ')}"
167
313
  raise ArgumentError, message
168
314
  end
169
315
 
@@ -171,38 +317,17 @@ module FreightKit
171
317
 
172
318
  if customer_location.present?
173
319
  unless customer_location.is_a?(Location)
174
- message = "#{self.class.name}#new: `customer_location` must be a Location"
320
+ message = "#{name}#new: `customer_location` must be a Location"
175
321
  raise ArgumentError, message
176
322
  end
177
323
 
178
324
  @customer_location = customer_location
179
325
  end
180
326
 
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
327
+ return if tariff.blank?
328
+ raise ArgumentError, "#{name}#new: `tariff` must be a Tariff" unless tariff.is_a?(Tariff)
199
329
 
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"
330
+ @tariff = tariff
206
331
  end
207
332
 
208
333
  # Asks the carrier for the bill of lading that the carrier would provide before shipping.
@@ -211,46 +336,7 @@ module FreightKit
211
336
  #
212
337
  # @param [String] tracking_number Tracking number.
213
338
  # @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
339
+ def bol(tracking_number) = raise NotImplementedError, "#{name}: #bol not supported"
254
340
 
255
341
  # Registers a new pickup with the carrier, to get a tracking number and
256
342
  # potentially shipping labels
@@ -283,19 +369,29 @@ module FreightKit
283
369
  service:,
284
370
  shipment:
285
371
  )
286
- raise NotImplementedError, "#create_pickup is not supported by #{self.class.name}."
372
+ raise NotImplementedError, "#create_pickup is not supported by #{name}."
287
373
  end
288
374
 
289
- # Cancels a shipment with a carrier.
375
+ # Fetch credential of given type.
290
376
  #
291
- # @note Override with whatever you need to cancel a shipping label
377
+ # @param type [Symbol] Type of credential to find, should be one of: `:api`, `:selenoid`, `:website`.
378
+ # @return [FreightKit::Credential|NilClass]
379
+ def fetch_credential(type) = credentials.find { |credential| credential.type == type }
380
+
381
+ # Asks the carrier for a list of locations (terminals) for a given country
292
382
  #
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
383
+ # @param [ActiveUtils::Country] country
384
+ # @return [Array<Location>]
385
+ def find_locations(country) = raise NotImplementedError, "#{name}: #find_locations not supported"
386
+
387
+ # Asks the carrier for rate estimates for a given shipment.
388
+ #
389
+ # @note Override with whatever you need to get the rates from the carrier.
390
+ #
391
+ # @param shipment [FreightKit::Shipment] Shipment details.
392
+ # @return [FreightKit::RateResponse] The response from the carrier, which
393
+ # includes 0 or more rate estimates for different shipping products
394
+ def find_rates(shipment:) = raise NotImplementedError, "#find_rates is not supported by #{name}."
299
395
 
300
396
  # Retrieves tracking information for a previous shipment
301
397
  #
@@ -305,189 +401,40 @@ module FreightKit
305
401
  # @return [FreightKit::TrackingResponse] The response from the carrier. This
306
402
  # response should a list of shipment tracking events if successful.
307
403
  def find_tracking_info(tracking_number)
308
- raise NotImplementedError, "#find_tracking_info is not supported by #{self.class.name}."
404
+ raise NotImplementedError, "#find_tracking_info is not supported by #{name}."
309
405
  end
310
406
 
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}."
407
+ def find_tracking_number_from_pickup_number(pickup_number, date)
408
+ raise NotImplementedError, "#{name}: #find_tracking_number_from_pickup_number not supported"
319
409
  end
320
410
 
321
- # Fetch credential of given type.
411
+ # Asks the carrier for the scanned proof of delivery that the carrier would provide after delivery.
322
412
  #
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
413
+ # @param [String] tracking_number Tracking number.
414
+ # @return [DocumentResponse]
415
+ def pod(tracking_number) = raise NotImplementedError, "#{name}: #pod not supported"
331
416
 
332
- # Validate credentials with a call to the API.
417
+ # Asks the carrier for the scanned bill of lading that the carrier would provide after shipping.
333
418
  #
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.
419
+ # @see #bol
336
420
  #
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
421
+ # @param [String] tracking_number Tracking number.
422
+ # @return [DocumentResponse]
423
+ def scanned_bol(tracking_number) = raise NotImplementedError, "#{name}: #scanned_bol not supported"
347
424
 
348
425
  # Validate the tracking number (may call API).
349
426
  #
350
427
  # @param [String] tracking_number Tracking number.
351
428
  # @return [Boolean] Should return `true` if the provided pro is valid.
352
429
  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
430
+ raise NotImplementedError, "#valid_tracking_number? is not supported by #{name}."
479
431
  end
480
432
 
481
433
  protected
482
434
 
483
- include ActiveUtils::RequiresParameters
484
- include ActiveUtils::PostsData
485
-
486
435
  # Use after building the request to save for later inspection.
487
436
  # @return [void]
488
- def save_request(request)
489
- @last_request = request
490
- end
437
+ def save_request(request) = @last_request = request
491
438
 
492
439
  # Calculates a timestamp that corresponds a given number of business days in the future
493
440
  #