@fleetbase/fleetops-engine 0.2.5 → 0.2.7

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 (325) hide show
  1. package/.gitattributes +14 -0
  2. package/.php-cs-fixer.cache +1 -0
  3. package/.php-cs-fixer.php +29 -0
  4. package/LICENSE.md +16 -4
  5. package/README.md +103 -13
  6. package/addon/components/admin/visibility-controls.hbs +12 -0
  7. package/addon/components/admin/visibility-controls.js +82 -0
  8. package/addon/components/fleet-panel.js +13 -4
  9. package/addon/components/fleet-vehicle-listing.hbs +1 -1
  10. package/addon/components/layout/fleet-ops-sidebar.hbs +26 -0
  11. package/addon/components/layout/fleet-ops-sidebar.js +129 -0
  12. package/addon/engine.js +19 -0
  13. package/addon/helpers/is-section-visible.js +5 -0
  14. package/addon/routes/application.js +6 -2
  15. package/addon/routes/virtual.js +10 -0
  16. package/addon/routes.js +1 -0
  17. package/addon/templates/application.hbs +1 -19
  18. package/addon/templates/virtual.hbs +9 -0
  19. package/app/components/admin/visibility-controls.js +1 -0
  20. package/app/components/layout/fleet-ops-sidebar.js +1 -0
  21. package/app/helpers/is-section-visible.js +1 -0
  22. package/app/routes/virtual.js +1 -0
  23. package/app/templates/virtual.js +1 -0
  24. package/composer.json +85 -0
  25. package/extension.json +10 -0
  26. package/package.json +6 -6
  27. package/phpstan.neon.dist +8 -0
  28. package/phpunit.xml.dist +16 -0
  29. package/server/config/api.php +765 -0
  30. package/server/config/cache.stores.php +18 -0
  31. package/server/config/dompdf.php +242 -0
  32. package/server/config/fleetops.php +19 -0
  33. package/server/config/geocoder.php +108 -0
  34. package/server/data/globe.json +261 -0
  35. package/server/migrations/2023_04_27_053456_create_contacts_table.php +49 -0
  36. package/server/migrations/2023_04_27_053456_create_drivers_table.php +62 -0
  37. package/server/migrations/2023_04_27_053456_create_entities_table.php +67 -0
  38. package/server/migrations/2023_04_27_053456_create_fleet_drivers_table.php +39 -0
  39. package/server/migrations/2023_04_27_053456_create_fleets_table.php +47 -0
  40. package/server/migrations/2023_04_27_053456_create_fuel_reports_table.php +50 -0
  41. package/server/migrations/2023_04_27_053456_create_integrated_vendors_table.php +44 -0
  42. package/server/migrations/2023_04_27_053456_create_issues_table.php +53 -0
  43. package/server/migrations/2023_04_27_053456_create_orders_table.php +70 -0
  44. package/server/migrations/2023_04_27_053456_create_payloads_table.php +51 -0
  45. package/server/migrations/2023_04_27_053456_create_places_table.php +62 -0
  46. package/server/migrations/2023_04_27_053456_create_positions_table.php +46 -0
  47. package/server/migrations/2023_04_27_053456_create_proofs_table.php +44 -0
  48. package/server/migrations/2023_04_27_053456_create_purchase_rates_table.php +46 -0
  49. package/server/migrations/2023_04_27_053456_create_routes_table.php +40 -0
  50. package/server/migrations/2023_04_27_053456_create_service_areas_table.php +47 -0
  51. package/server/migrations/2023_04_27_053456_create_service_quote_items_table.php +42 -0
  52. package/server/migrations/2023_04_27_053456_create_service_quotes_table.php +47 -0
  53. package/server/migrations/2023_04_27_053456_create_service_rate_fees_table.php +45 -0
  54. package/server/migrations/2023_04_27_053456_create_service_rate_parcel_fees_table.php +47 -0
  55. package/server/migrations/2023_04_27_053456_create_service_rates_table.php +61 -0
  56. package/server/migrations/2023_04_27_053456_create_tracking_numbers_table.php +46 -0
  57. package/server/migrations/2023_04_27_053456_create_tracking_statuses_table.php +54 -0
  58. package/server/migrations/2023_04_27_053456_create_vehicles_table.php +84 -0
  59. package/server/migrations/2023_04_27_053456_create_vendors_table.php +56 -0
  60. package/server/migrations/2023_04_27_053456_create_waypoints_table.php +45 -0
  61. package/server/migrations/2023_04_27_053456_create_zones_table.php +46 -0
  62. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_companies_table.php +32 -0
  63. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_contacts_table.php +34 -0
  64. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_drivers_table.php +40 -0
  65. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_entities_table.php +40 -0
  66. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_fleet_drivers_table.php +34 -0
  67. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_fleets_table.php +36 -0
  68. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_fuel_reports_table.php +36 -0
  69. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_integrated_vendors_table.php +34 -0
  70. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_issues_table.php +38 -0
  71. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_orders_table.php +48 -0
  72. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_payloads_table.php +40 -0
  73. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_places_table.php +32 -0
  74. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_positions_table.php +36 -0
  75. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_proofs_table.php +34 -0
  76. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_purchase_rates_table.php +38 -0
  77. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_routes_table.php +34 -0
  78. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_service_areas_table.php +34 -0
  79. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_service_quote_items_table.php +32 -0
  80. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_service_quotes_table.php +38 -0
  81. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_service_rate_fees_table.php +32 -0
  82. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_service_rate_parcel_fees_table.php +32 -0
  83. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_service_rates_table.php +36 -0
  84. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_tracking_numbers_table.php +34 -0
  85. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_tracking_statuses_table.php +34 -0
  86. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_vehicles_table.php +36 -0
  87. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_vendors_table.php +40 -0
  88. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_waypoints_table.php +38 -0
  89. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_zones_table.php +34 -0
  90. package/server/migrations/2023_09_14_074512_update_vehicles_table.php +100 -0
  91. package/server/migrations/2023_09_14_074619_create_vehicle_devices_table.php +44 -0
  92. package/server/migrations/2023_09_26_071205_add_online_column_to_vehicles_table.php +32 -0
  93. package/server/migrations/2023_09_26_083957_create_fleet_vehicles_table.php +45 -0
  94. package/server/migrations/2023_09_27_023757_add_column_to_fleets_table.php +46 -0
  95. package/server/migrations/2023_10_05_074811_update_vehicle.php +42 -0
  96. package/server/resources/views/labels/default.php +165 -0
  97. package/server/src/Auth/Schemas/FleetOps.php +75 -0
  98. package/server/src/Casts/MultiPolygon.php +50 -0
  99. package/server/src/Casts/Point.php +109 -0
  100. package/server/src/Casts/Polygon.php +46 -0
  101. package/server/src/Console/Commands/DispatchAdhocOrders.php +137 -0
  102. package/server/src/Console/Commands/DispatchOrders.php +71 -0
  103. package/server/src/Console/Commands/TrackOrderDistanceAndTime.php +62 -0
  104. package/server/src/Events/DriverLocationChanged.php +174 -0
  105. package/server/src/Events/DriverSimulatedLocationChanged.php +183 -0
  106. package/server/src/Events/EntityDriverAssigned.php +36 -0
  107. package/server/src/Events/OrderCanceled.php +15 -0
  108. package/server/src/Events/OrderCompleted.php +15 -0
  109. package/server/src/Events/OrderDispatchFailed.php +42 -0
  110. package/server/src/Events/OrderDispatched.php +15 -0
  111. package/server/src/Events/OrderDriverAssigned.php +15 -0
  112. package/server/src/Events/OrderReady.php +15 -0
  113. package/server/src/Events/OrderStarted.php +15 -0
  114. package/server/src/Exceptions/IntegratedVendorException.php +18 -0
  115. package/server/src/Expansions/UserExpansion.php +63 -0
  116. package/server/src/Exports/ContactExport.php +56 -0
  117. package/server/src/Exports/DriverExport.php +61 -0
  118. package/server/src/Exports/FleetExport.php +53 -0
  119. package/server/src/Exports/PlaceExport.php +55 -0
  120. package/server/src/Exports/ServiceAreaExport.php +58 -0
  121. package/server/src/Exports/VehicleExport.php +57 -0
  122. package/server/src/Exports/VendorExport.php +57 -0
  123. package/server/src/Http/Controllers/Api/v1/ContactController.php +133 -0
  124. package/server/src/Http/Controllers/Api/v1/DriverController.php +691 -0
  125. package/server/src/Http/Controllers/Api/v1/EntityController.php +230 -0
  126. package/server/src/Http/Controllers/Api/v1/FleetController.php +146 -0
  127. package/server/src/Http/Controllers/Api/v1/LabelController.php +63 -0
  128. package/server/src/Http/Controllers/Api/v1/OrderController.php +1114 -0
  129. package/server/src/Http/Controllers/Api/v1/PayloadController.php +195 -0
  130. package/server/src/Http/Controllers/Api/v1/PlaceController.php +333 -0
  131. package/server/src/Http/Controllers/Api/v1/PurchaseRateController.php +199 -0
  132. package/server/src/Http/Controllers/Api/v1/ServiceAreaController.php +133 -0
  133. package/server/src/Http/Controllers/Api/v1/ServiceQuoteController.php +381 -0
  134. package/server/src/Http/Controllers/Api/v1/ServiceRateController.php +223 -0
  135. package/server/src/Http/Controllers/Api/v1/TrackingNumberController.php +146 -0
  136. package/server/src/Http/Controllers/Api/v1/TrackingStatusController.php +138 -0
  137. package/server/src/Http/Controllers/Api/v1/VehicleController.php +191 -0
  138. package/server/src/Http/Controllers/Api/v1/VendorController.php +159 -0
  139. package/server/src/Http/Controllers/Api/v1/ZoneController.php +146 -0
  140. package/server/src/Http/Controllers/FleetOpsController.php +13 -0
  141. package/server/src/Http/Controllers/Internal/v1/ContactController.php +69 -0
  142. package/server/src/Http/Controllers/Internal/v1/DriverController.php +261 -0
  143. package/server/src/Http/Controllers/Internal/v1/EntityController.php +15 -0
  144. package/server/src/Http/Controllers/Internal/v1/FleetController.php +152 -0
  145. package/server/src/Http/Controllers/Internal/v1/FleetOpsLookupController.php +80 -0
  146. package/server/src/Http/Controllers/Internal/v1/FuelReportController.php +15 -0
  147. package/server/src/Http/Controllers/Internal/v1/GeocoderController.php +96 -0
  148. package/server/src/Http/Controllers/Internal/v1/IntegratedVendorController.php +63 -0
  149. package/server/src/Http/Controllers/Internal/v1/IssueController.php +15 -0
  150. package/server/src/Http/Controllers/Internal/v1/LiveController.php +127 -0
  151. package/server/src/Http/Controllers/Internal/v1/MetricsController.php +75 -0
  152. package/server/src/Http/Controllers/Internal/v1/MorphController.php +77 -0
  153. package/server/src/Http/Controllers/Internal/v1/OrderConfigController.php +269 -0
  154. package/server/src/Http/Controllers/Internal/v1/OrderController.php +564 -0
  155. package/server/src/Http/Controllers/Internal/v1/PayloadController.php +15 -0
  156. package/server/src/Http/Controllers/Internal/v1/PlaceController.php +163 -0
  157. package/server/src/Http/Controllers/Internal/v1/ProofController.php +139 -0
  158. package/server/src/Http/Controllers/Internal/v1/PurchaseRateController.php +15 -0
  159. package/server/src/Http/Controllers/Internal/v1/RouteController.php +15 -0
  160. package/server/src/Http/Controllers/Internal/v1/ServiceAreaController.php +32 -0
  161. package/server/src/Http/Controllers/Internal/v1/ServiceQuoteController.php +345 -0
  162. package/server/src/Http/Controllers/Internal/v1/ServiceRateController.php +47 -0
  163. package/server/src/Http/Controllers/Internal/v1/SettingController.php +30 -0
  164. package/server/src/Http/Controllers/Internal/v1/TrackingNumberController.php +15 -0
  165. package/server/src/Http/Controllers/Internal/v1/TrackingStatusController.php +15 -0
  166. package/server/src/Http/Controllers/Internal/v1/VehicleController.php +65 -0
  167. package/server/src/Http/Controllers/Internal/v1/VehicleDeviceController.php +15 -0
  168. package/server/src/Http/Controllers/Internal/v1/VendorController.php +120 -0
  169. package/server/src/Http/Controllers/Internal/v1/ZoneController.php +15 -0
  170. package/server/src/Http/Filter/ContactFilter.php +86 -0
  171. package/server/src/Http/Filter/DriverFilter.php +148 -0
  172. package/server/src/Http/Filter/FleetFilter.php +108 -0
  173. package/server/src/Http/Filter/IntegratedVendorFilter.php +13 -0
  174. package/server/src/Http/Filter/OrderFilter.php +242 -0
  175. package/server/src/Http/Filter/PlaceFilter.php +111 -0
  176. package/server/src/Http/Filter/ServiceAreaFilter.php +13 -0
  177. package/server/src/Http/Filter/ServiceQuoteFilter.php +13 -0
  178. package/server/src/Http/Filter/ServiceRateFilter.php +33 -0
  179. package/server/src/Http/Filter/TrackingStatusFilter.php +43 -0
  180. package/server/src/Http/Filter/VehicleFilter.php +91 -0
  181. package/server/src/Http/Filter/VendorFilter.php +83 -0
  182. package/server/src/Http/Filter/ZoneFilter.php +13 -0
  183. package/server/src/Http/Requests/CancelOrderRequest.php +31 -0
  184. package/server/src/Http/Requests/CreateContactRequest.php +33 -0
  185. package/server/src/Http/Requests/CreateDriverRequest.php +55 -0
  186. package/server/src/Http/Requests/CreateEntityRequest.php +43 -0
  187. package/server/src/Http/Requests/CreateFleetRequest.php +32 -0
  188. package/server/src/Http/Requests/CreateOrderRequest.php +66 -0
  189. package/server/src/Http/Requests/CreatePayloadRequest.php +37 -0
  190. package/server/src/Http/Requests/CreatePlaceRequest.php +38 -0
  191. package/server/src/Http/Requests/CreatePurchaseRateRequest.php +33 -0
  192. package/server/src/Http/Requests/CreateServiceAreaRequest.php +35 -0
  193. package/server/src/Http/Requests/CreateServiceQuoteRequest.php +29 -0
  194. package/server/src/Http/Requests/CreateServiceRateRequest.php +56 -0
  195. package/server/src/Http/Requests/CreateTrackingNumberRequest.php +34 -0
  196. package/server/src/Http/Requests/CreateTrackingStatusRequest.php +42 -0
  197. package/server/src/Http/Requests/CreateVehicleRequest.php +32 -0
  198. package/server/src/Http/Requests/CreateVendorRequest.php +35 -0
  199. package/server/src/Http/Requests/CreateZoneRequest.php +35 -0
  200. package/server/src/Http/Requests/DecodeTrackingNumberQR.php +30 -0
  201. package/server/src/Http/Requests/DriverSimulationRequest.php +46 -0
  202. package/server/src/Http/Requests/Internal/AssignOrderRequest.php +31 -0
  203. package/server/src/Http/Requests/Internal/CreateDriverRequest.php +42 -0
  204. package/server/src/Http/Requests/Internal/FleetActionRequest.php +32 -0
  205. package/server/src/Http/Requests/Internal/UpdateDriverRequest.php +7 -0
  206. package/server/src/Http/Requests/QueryServiceQuotesRequest.php +41 -0
  207. package/server/src/Http/Requests/UpdateContactRequest.php +20 -0
  208. package/server/src/Http/Requests/UpdateDriverRequest.php +7 -0
  209. package/server/src/Http/Requests/UpdateEntityRequest.php +7 -0
  210. package/server/src/Http/Requests/UpdateFleetRequest.php +7 -0
  211. package/server/src/Http/Requests/UpdateOrderRequest.php +7 -0
  212. package/server/src/Http/Requests/UpdatePayloadRequest.php +7 -0
  213. package/server/src/Http/Requests/UpdatePlaceRequest.php +7 -0
  214. package/server/src/Http/Requests/UpdatePurchaseRateRequest.php +7 -0
  215. package/server/src/Http/Requests/UpdateServiceAreaRequest.php +29 -0
  216. package/server/src/Http/Requests/UpdateServiceQuoteRequest.php +29 -0
  217. package/server/src/Http/Requests/UpdateServiceRateRequest.php +29 -0
  218. package/server/src/Http/Requests/UpdateTrackingNumberRequest.php +7 -0
  219. package/server/src/Http/Requests/UpdateTrackingStatusRequest.php +32 -0
  220. package/server/src/Http/Requests/UpdateVehicleRequest.php +7 -0
  221. package/server/src/Http/Requests/UpdateVendorRequest.php +7 -0
  222. package/server/src/Http/Requests/UpdateZoneRequest.php +7 -0
  223. package/server/src/Http/Resources/Internal/v1/IntegratedVendorFacilitator.php +37 -0
  224. package/server/src/Http/Resources/Internal/v1/Vehicle.php +33 -0
  225. package/server/src/Http/Resources/Internal/v1/Waypoint.php +34 -0
  226. package/server/src/Http/Resources/v1/Contact.php +62 -0
  227. package/server/src/Http/Resources/v1/CurrentJob.php +36 -0
  228. package/server/src/Http/Resources/v1/DeletedResource.php +61 -0
  229. package/server/src/Http/Resources/v1/Driver.php +89 -0
  230. package/server/src/Http/Resources/v1/Entity.php +107 -0
  231. package/server/src/Http/Resources/v1/Fleet.php +60 -0
  232. package/server/src/Http/Resources/v1/FuelReport.php +67 -0
  233. package/server/src/Http/Resources/v1/Order.php +131 -0
  234. package/server/src/Http/Resources/v1/Payload.php +94 -0
  235. package/server/src/Http/Resources/v1/Place.php +84 -0
  236. package/server/src/Http/Resources/v1/Proof.php +36 -0
  237. package/server/src/Http/Resources/v1/PurchaseRate.php +77 -0
  238. package/server/src/Http/Resources/v1/ServiceArea.php +55 -0
  239. package/server/src/Http/Resources/v1/ServiceQuote.php +57 -0
  240. package/server/src/Http/Resources/v1/ServiceRate.php +94 -0
  241. package/server/src/Http/Resources/v1/ServiceRateFee.php +58 -0
  242. package/server/src/Http/Resources/v1/ServiceRateParcelFee.php +48 -0
  243. package/server/src/Http/Resources/v1/TrackingNumber.php +62 -0
  244. package/server/src/Http/Resources/v1/TrackingStatus.php +84 -0
  245. package/server/src/Http/Resources/v1/Vehicle.php +75 -0
  246. package/server/src/Http/Resources/v1/VehicleDevice.php +44 -0
  247. package/server/src/Http/Resources/v1/VehicleWithoutDriver.php +72 -0
  248. package/server/src/Http/Resources/v1/Vendor.php +72 -0
  249. package/server/src/Http/Resources/v1/Zone.php +60 -0
  250. package/server/src/Imports/OrdersImport.php +18 -0
  251. package/server/src/Integrations/Lalamove/Lalamove.php +678 -0
  252. package/server/src/Integrations/Lalamove/LalamoveDeliveryStop.php +97 -0
  253. package/server/src/Integrations/Lalamove/LalamoveMarket.php +123 -0
  254. package/server/src/Integrations/Lalamove/LalamoveServiceType.php +161 -0
  255. package/server/src/Jobs/SimulateDrivingRoute.php +81 -0
  256. package/server/src/Jobs/SimulateWaypointReached.php +79 -0
  257. package/server/src/Listeners/HandleOrderCanceled.php +46 -0
  258. package/server/src/Listeners/HandleOrderCreated.php +23 -0
  259. package/server/src/Listeners/HandleOrderDispatchFailed.php +35 -0
  260. package/server/src/Listeners/HandleOrderDispatched.php +108 -0
  261. package/server/src/Listeners/HandleOrderDriverAssigned.php +42 -0
  262. package/server/src/Listeners/HandleOrderReady.php +27 -0
  263. package/server/src/Listeners/HandleUserRemovedFromCompany.php +31 -0
  264. package/server/src/Models/Contact.php +239 -0
  265. package/server/src/Models/Driver.php +543 -0
  266. package/server/src/Models/Entity.php +416 -0
  267. package/server/src/Models/Fleet.php +203 -0
  268. package/server/src/Models/FleetDriver.php +73 -0
  269. package/server/src/Models/FleetVehicle.php +73 -0
  270. package/server/src/Models/FuelReport.php +125 -0
  271. package/server/src/Models/IntegratedVendor.php +219 -0
  272. package/server/src/Models/Issue.php +111 -0
  273. package/server/src/Models/Order.php +1132 -0
  274. package/server/src/Models/Payload.php +699 -0
  275. package/server/src/Models/Place.php +656 -0
  276. package/server/src/Models/Position.php +119 -0
  277. package/server/src/Models/Proof.php +94 -0
  278. package/server/src/Models/PurchaseRate.php +208 -0
  279. package/server/src/Models/Route.php +128 -0
  280. package/server/src/Models/ServiceArea.php +161 -0
  281. package/server/src/Models/ServiceQuote.php +207 -0
  282. package/server/src/Models/ServiceQuoteItem.php +46 -0
  283. package/server/src/Models/ServiceRate.php +953 -0
  284. package/server/src/Models/ServiceRateFee.php +96 -0
  285. package/server/src/Models/ServiceRateParcelFee.php +116 -0
  286. package/server/src/Models/TrackingNumber.php +310 -0
  287. package/server/src/Models/TrackingStatus.php +177 -0
  288. package/server/src/Models/Vehicle.php +452 -0
  289. package/server/src/Models/VehicleDevice.php +79 -0
  290. package/server/src/Models/Vendor.php +244 -0
  291. package/server/src/Models/Waypoint.php +226 -0
  292. package/server/src/Models/Zone.php +95 -0
  293. package/server/src/Notifications/OrderAssigned.php +140 -0
  294. package/server/src/Notifications/OrderCanceled.php +129 -0
  295. package/server/src/Notifications/OrderDispatchFailed.php +81 -0
  296. package/server/src/Notifications/OrderDispatched.php +173 -0
  297. package/server/src/Notifications/OrderPing.php +162 -0
  298. package/server/src/Notifications/OrderSplit.php +56 -0
  299. package/server/src/Observers/DriverObserver.php +34 -0
  300. package/server/src/Observers/OrderObserver.php +34 -0
  301. package/server/src/Observers/PayloadObserver.php +30 -0
  302. package/server/src/Observers/PlaceObserver.php +26 -0
  303. package/server/src/Observers/PurchaseRateObserver.php +61 -0
  304. package/server/src/Observers/ServiceAreaObserver.php +35 -0
  305. package/server/src/Observers/ServiceRateObserver.php +78 -0
  306. package/server/src/Observers/TrackingNumberObserver.php +44 -0
  307. package/server/src/Observers/UserObserver.php +20 -0
  308. package/server/src/Observers/VehicleObserver.php +66 -0
  309. package/server/src/Providers/EventServiceProvider.php +30 -0
  310. package/server/src/Providers/FleetOpsServiceProvider.php +94 -0
  311. package/server/src/Rules/ResolvablePoint.php +37 -0
  312. package/server/src/Scopes/DriverScope.php +21 -0
  313. package/server/src/Support/Algo.php +55 -0
  314. package/server/src/Support/DistanceMatrix.php +27 -0
  315. package/server/src/Support/Encoding/Polyline.php +168 -0
  316. package/server/src/Support/Flow.php +622 -0
  317. package/server/src/Support/Geocoding.php +216 -0
  318. package/server/src/Support/IntegratedVendors.php +287 -0
  319. package/server/src/Support/Metrics.php +305 -0
  320. package/server/src/Support/OSRM.php +191 -0
  321. package/server/src/Support/ParsePhone.php +21 -0
  322. package/server/src/Support/Utils.php +1145 -0
  323. package/server/src/Traits/HasTrackingNumber.php +185 -0
  324. package/server/src/routes.php +381 -0
  325. package/server/tests/Feature.php +5 -0
@@ -0,0 +1,656 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Models;
4
+
5
+ use Fleetbase\Casts\Json;
6
+ use Fleetbase\FleetOps\Casts\Point;
7
+ use Fleetbase\FleetOps\Support\Utils;
8
+ use Fleetbase\Models\Model;
9
+ use Fleetbase\Traits\HasApiModelBehavior;
10
+ use Fleetbase\Traits\HasMetaAttributes;
11
+ use Fleetbase\Traits\HasPublicId;
12
+ use Fleetbase\Traits\HasUuid;
13
+ use Fleetbase\Traits\Searchable;
14
+ use Fleetbase\Traits\SendsWebhooks;
15
+ use Fleetbase\Traits\TracksApiCredential;
16
+ use Grimzy\LaravelMysqlSpatial\Eloquent\SpatialTrait;
17
+ use Illuminate\Support\Carbon;
18
+ use Illuminate\Support\Facades\DB;
19
+ use Illuminate\Support\Str;
20
+
21
+ class Place extends Model
22
+ {
23
+ use HasUuid;
24
+ use HasPublicId;
25
+ use HasApiModelBehavior;
26
+ use Searchable;
27
+ use SendsWebhooks;
28
+ use TracksApiCredential;
29
+ use SpatialTrait;
30
+ use HasMetaAttributes;
31
+
32
+ /**
33
+ * The database table used by the model.
34
+ *
35
+ * @var string
36
+ */
37
+ protected $table = 'places';
38
+
39
+ /**
40
+ * The type of public Id to generate.
41
+ *
42
+ * @var string
43
+ */
44
+ protected $publicIdType = 'place';
45
+
46
+ /**
47
+ * The attributes that can be queried.
48
+ *
49
+ * @var array
50
+ */
51
+ protected $searchableColumns = ['name', 'street1', 'street2', 'country', 'province', 'district', 'city', 'postal_code', 'phone'];
52
+
53
+ /**
54
+ * The attributes that are spatial columns.
55
+ *
56
+ * @var array
57
+ */
58
+ protected $spatialFields = ['location'];
59
+
60
+ /**
61
+ * The attributes that are mass assignable.
62
+ *
63
+ * @var array
64
+ */
65
+ protected $fillable = [
66
+ '_key',
67
+ '_import_id',
68
+ 'company_uuid',
69
+ 'owner_uuid',
70
+ 'owner_type',
71
+ 'name',
72
+ 'type',
73
+ 'street1',
74
+ 'street2',
75
+ 'city',
76
+ 'province',
77
+ 'postal_code',
78
+ 'neighborhood',
79
+ 'district',
80
+ 'building',
81
+ 'security_access_code',
82
+ 'country',
83
+ 'location',
84
+ 'meta',
85
+ 'phone',
86
+ ];
87
+
88
+ /**
89
+ * Dynamic attributes that are appended to object.
90
+ *
91
+ * @var array
92
+ */
93
+ protected $appends = ['country_name', 'address', 'address_html'];
94
+
95
+ /**
96
+ * The attributes excluded from the model's JSON form.
97
+ *
98
+ * @var array
99
+ */
100
+ protected $hidden = [
101
+ 'id',
102
+ '_key',
103
+ 'connect_company_uuid',
104
+ 'owner_uuid',
105
+ 'owner_type',
106
+ ];
107
+
108
+ /**
109
+ * The attributes that should be cast to native types.
110
+ *
111
+ * @var array
112
+ */
113
+ protected $casts = [
114
+ 'meta' => Json::class,
115
+ 'location' => Point::class,
116
+ ];
117
+
118
+ /**
119
+ * Attributes that is filterable on this model.
120
+ *
121
+ * @var array
122
+ */
123
+ protected $filterParams = ['vendor', 'contact', 'vendor_uuid', 'vendor_name'];
124
+
125
+ /**
126
+ * @return \Illuminate\Database\Eloquent\Relations\MorphTo
127
+ */
128
+ public function owner()
129
+ {
130
+ return $this->morphTo(__FILE__, 'owner_type', 'owner_uuid')->withDefault(
131
+ [
132
+ 'name' => 'N/A',
133
+ ]
134
+ );
135
+ }
136
+
137
+ /**
138
+ * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
139
+ */
140
+ public function company()
141
+ {
142
+ return $this->belongsTo(\Fleetbase\Models\Company::class);
143
+ }
144
+
145
+ /**
146
+ * Get the country data for the model instance.
147
+ */
148
+ public function getCountryDataAttribute(): array
149
+ {
150
+ return $this->fromCache(
151
+ 'country_data',
152
+ function () {
153
+ if (empty($this->country)) {
154
+ return [];
155
+ }
156
+
157
+ return Utils::getCountryData($this->country);
158
+ }
159
+ );
160
+ }
161
+
162
+ /**
163
+ * Returns the full country name.
164
+ */
165
+ public function getCountryNameAttribute(): ?string
166
+ {
167
+ return data_get($this, 'country_data.name.common');
168
+ }
169
+
170
+ /**
171
+ * Returns a Point instance from the location of the model.
172
+ */
173
+ public function getLocationAsPoint(): \Grimzy\LaravelMysqlSpatial\Types\Point
174
+ {
175
+ return Utils::getPointFromCoordinates($this->location);
176
+ }
177
+
178
+ /**
179
+ * Fills empty address attributes with Google address attributes.
180
+ *
181
+ * @return \Fleetbase\FleetOps\Models\Place $this
182
+ */
183
+ public function fillWithGoogleAddress(\Geocoder\Provider\GoogleMaps\Model\GoogleAddress $address): Place
184
+ {
185
+ $formattedAddress = $address->getFormattedAddress();
186
+
187
+ if (empty($this->street1) && $address) {
188
+ $streetAddress = trim($address->getStreetAddress() ?? $address->getStreetNumber() . ' ' . $address->getStreetName());
189
+
190
+ if (empty($streetAddress) && $formattedAddress) {
191
+ // fallback use `formattedAddress`
192
+ $streetAddress = explode(',', $formattedAddress, 3);
193
+ $streetAddress = isset($streetAddress[2]) ? trim($streetAddress[0] . ', ' . $streetAddress[1]) : $formattedAddress;
194
+ }
195
+
196
+ $this->setAttribute('street1', $streetAddress);
197
+ }
198
+
199
+ if (empty($this->postal_code) && $address) {
200
+ $this->setAttribute('postal_code', $address->getPostalCode());
201
+ }
202
+
203
+ if (empty($this->neighborhood) && $address) {
204
+ $this->setAttribute('neighborhood', $address->getNeighborhood());
205
+ }
206
+
207
+ if (empty($this->city) && $address) {
208
+ $this->setAttribute('city', $address->getLocality());
209
+ }
210
+
211
+ if (empty($this->building) && $address) {
212
+ $this->setAttribute('building', $address->getStreetNumber());
213
+ }
214
+
215
+ if (empty($this->country) && $address) {
216
+ $this->setAttribute('country', $address->getCountry()->getCode());
217
+ }
218
+
219
+ if ($coordinates = $address->getCoordinates()) {
220
+ $this->setAttribute('location', new \Grimzy\LaravelMysqlSpatial\Types\Point($coordinates->getLatitude(), $coordinates->getLongitude()));
221
+ }
222
+
223
+ return $this;
224
+ }
225
+
226
+ /**
227
+ * Returns an array of address attributes using Google address object.
228
+ */
229
+ public static function getGoogleAddressArray(?\Geocoder\Provider\GoogleMaps\Model\GoogleAddress $address): array
230
+ {
231
+ $attributes = [];
232
+
233
+ if (!$address instanceof \Geocoder\Provider\GoogleMaps\Model\GoogleAddress) {
234
+ return $attributes;
235
+ }
236
+
237
+ $stretAddress = $address->getStreetAddress() ?? $address->getStreetNumber() . ' ' . $address->getStreetName();
238
+ $coordinates = $address->getCoordinates();
239
+
240
+ $attributes['name'] = $stretAddress;
241
+ $attributes['street1'] = $stretAddress;
242
+ $attributes['postal_code'] = $address->getPostalCode();
243
+ $attributes['neighborhood'] = $address->getNeighborhood();
244
+ $attributes['city'] = $address->getLocality();
245
+ $attributes['building'] = $address->getStreetNumber();
246
+ $attributes['country'] = $address->getCountry()->getCode();
247
+ $attributes['location'] = new \Grimzy\LaravelMysqlSpatial\Types\Point($coordinates->getLatitude(), $coordinates->getLongitude());
248
+
249
+ return $attributes;
250
+ }
251
+
252
+ /**
253
+ * Create a new Place instance from a Google Address instance and optionally save it to the database.
254
+ */
255
+ public static function createFromGoogleAddress(\Geocoder\Provider\GoogleMaps\Model\GoogleAddress $address, bool $saveInstance = false): Place
256
+ {
257
+ $instance = (new static())->fillWithGoogleAddress($address);
258
+
259
+ if ($saveInstance) {
260
+ $instance->save();
261
+ }
262
+
263
+ return $instance;
264
+ }
265
+
266
+ /**
267
+ * Inserts a new Place record into the database with attributes from a Google Maps address.
268
+ *
269
+ * @return string The UUID of the new record
270
+ */
271
+ public static function insertFromGoogleAddress(\Geocoder\Provider\GoogleMaps\Model\GoogleAddress $address)
272
+ {
273
+ $values = static::getGoogleAddressArray($address);
274
+
275
+ return static::insertGetUuid($values);
276
+ }
277
+
278
+ /**
279
+ * Create a new Place instance from a geocoding lookup.
280
+ *
281
+ * @param bool $saveInstance
282
+ */
283
+ public static function createFromGeocodingLookup(string $address, $saveInstance = false): Place
284
+ {
285
+ $results = \Geocoder\Laravel\Facades\Geocoder::geocode($address)->get();
286
+
287
+ if ($results->isEmpty() || !$results->first()) {
288
+ return (new static())->newInstance(['street1' => $address]);
289
+ }
290
+
291
+ return static::createFromGoogleAddress($results->first(), $saveInstance);
292
+ }
293
+
294
+ /**
295
+ * Creates a new Place instance from given coordinates.
296
+ *
297
+ * @param array $attributes
298
+ * @param bool $saveInstance
299
+ *
300
+ * @return Place|false
301
+ */
302
+ public static function createFromCoordinates($coordinates, $attributes = [], $saveInstance = false)
303
+ {
304
+ $instance = new Place();
305
+
306
+ $latitude = Utils::getLatitudeFromCoordinates($coordinates);
307
+ $longitude = Utils::getLongitudeFromCoordinates($coordinates);
308
+
309
+ $instance->setAttribute('location', new \Grimzy\LaravelMysqlSpatial\Types\Point($latitude, $longitude));
310
+ $instance->fill($attributes);
311
+
312
+ $results = \Geocoder\Laravel\Facades\Geocoder::reverse($latitude, $longitude)->get();
313
+
314
+ if ($results->isEmpty()) {
315
+ return false;
316
+ }
317
+
318
+ $instance->fillWithGoogleAddress($results->first());
319
+
320
+ if ($saveInstance) {
321
+ $instance->save();
322
+ }
323
+
324
+ return $instance;
325
+ }
326
+
327
+ /**
328
+ * Inserts a new place into the database using latitude and longitude coordinates.
329
+ *
330
+ * @param \Grimzy\LaravelMysqlSpatial\Types\Point|string|array $coordinates the coordinates to use for the new place
331
+ *
332
+ * @return mixed returns the UUID of the new place on success or false on failure
333
+ */
334
+ public static function insertFromCoordinates($coordinates)
335
+ {
336
+ $attributes = [];
337
+
338
+ $point = Utils::getPointFromMixed($coordinates);
339
+
340
+ if ($coordinates instanceof \Grimzy\LaravelMysqlSpatial\Types\Point) {
341
+ $attributes['location'] = $coordinates;
342
+ $latitude = $coordinates->getLat();
343
+ $longitude = $coordinates->getLng();
344
+ } elseif ($point instanceof \Grimzy\LaravelMysqlSpatial\Types\Point) {
345
+ $attributes['location'] = $point;
346
+ $latitude = $point->getLat();
347
+ $longitude = $point->getLng();
348
+ }
349
+
350
+ $results = \Geocoder\Laravel\Facades\Geocoder::reverse($latitude, $longitude)->get();
351
+
352
+ if (!$results->count() === 0) {
353
+ return false;
354
+ }
355
+
356
+ $address = static::getGoogleAddressArray($results->first());
357
+ $values = array_merge($attributes, $address);
358
+
359
+ return static::insertGetUuid($values);
360
+ }
361
+
362
+ /**
363
+ * Creates a Place object from mixed input.
364
+ *
365
+ * @param array $attributes
366
+ * @param bool $saveInstance
367
+ *
368
+ * @return \App\Models\Place|false
369
+ */
370
+ public static function createFromMixed($place, $attributes = [], $saveInstance = true)
371
+ {
372
+ // If $place is a string
373
+ if (is_string($place)) {
374
+ // Check if $place is a valid public_id, return matching Place object if found
375
+ if (Utils::isPublicId($place)) {
376
+ return Place::where('public_id', $place)->first();
377
+ }
378
+
379
+ // Check if $place is a valid uuid, return matching Place object if found
380
+ if (Str::isUuid($place)) {
381
+ return Place::where('uuid', $place)->first();
382
+ }
383
+
384
+ // Attempt to find by address or name
385
+ $resolvedFromSearch = static::query()
386
+ ->where('company_uuid', session('company'))
387
+ ->where(function ($q) use ($place) {
388
+ $q->where('street1', $place);
389
+ $q->orWhere('name', $place);
390
+ })
391
+ ->first();
392
+
393
+ if ($resolvedFromSearch) {
394
+ return $resolvedFromSearch;
395
+ }
396
+
397
+ // Return a new Place object created from a geocoding lookup
398
+ return static::createFromGeocodingLookup($place, $saveInstance);
399
+ }
400
+ // If $place is an array of coordinates
401
+ elseif (Utils::isCoordinatesStrict($place)) {
402
+ return static::insertFromCoordinates($place, true);
403
+ }
404
+ // If $place is an array
405
+ elseif (is_array($place)) {
406
+ // If $place is an array of coordinates, create a new Place object
407
+ if (Utils::isCoordinatesStrict($place)) {
408
+ return static::createFromCoordinates($place, $attributes, $saveInstance);
409
+ }
410
+
411
+ // If $place has a valid uuid and a matching Place object exists, return the uuid
412
+ if (isset($place['uuid']) && Str::isUuid($place['uuid']) && Place::where('uuid', $place['uuid'])->exists()) {
413
+ return $place['uuid'];
414
+ }
415
+
416
+ // Otherwise, create a new Place object with the given attributes
417
+ return Place::create($place);
418
+ }
419
+ // If $place is a GoogleAddress object
420
+ elseif ($place instanceof \Geocoder\Provider\GoogleMaps\Model\GoogleAddress) {
421
+ return static::createFromGoogleAddress($place, $saveInstance);
422
+ }
423
+
424
+ return false;
425
+ }
426
+
427
+ /**
428
+ * Inserts a new place into the database from mixed data.
429
+ *
430
+ * @param mixed $place the data to use to create the new place
431
+ *
432
+ * @return string|bool the UUID of the newly created place or false if the place was not created
433
+ */
434
+ public static function insertFromMixed($place)
435
+ {
436
+ if (Utils::isCoordinatesStrict($place)) {
437
+ // create a place from coordinates using reverse loopup
438
+ return Place::insertFromCoordinates($place, true);
439
+ } elseif (is_string($place)) {
440
+ if (Utils::isPublicId($place)) {
441
+ $resolvedPlace = Place::where('public_id', $place)->first();
442
+
443
+ if ($resolvedPlace) {
444
+ return $resolvedPlace->uuid;
445
+ }
446
+ }
447
+
448
+ if (Str::isUuid($place)) {
449
+ $resolvedPlace = Place::where('uuid', $place)->first();
450
+
451
+ if ($resolvedPlace) {
452
+ return $resolvedPlace->uuid;
453
+ }
454
+ }
455
+
456
+ return Place::insertFromGeocodingLookup($place);
457
+ } elseif (is_array($place) || is_object($place)) {
458
+ // if place already exists just return uuid
459
+ if (static::isValidPlaceUuid(data_get($place, 'uuid'))) {
460
+ return data_get($place, 'uuid');
461
+ }
462
+
463
+ // if place already exists using `public_id` then resolve and return uuid
464
+ if (static::isValidPlacePublicId(data_get($place, 'public_id'))) {
465
+ $resolvedPlace = static::where('public_id', data_get($place, 'public_id'))->first();
466
+
467
+ if ($resolvedPlace) {
468
+ return $resolvedPlace->uuid;
469
+ }
470
+ }
471
+
472
+ $values = $place;
473
+
474
+ // create a new place
475
+ return static::insertGetUuid((array) $values);
476
+ } elseif ($place instanceof \Geocoder\Provider\GoogleMaps\Model\GoogleAddress) {
477
+ return static::insertFromGoogleAddress($place);
478
+ }
479
+ }
480
+
481
+ public static function isValidPlaceUuid($uuid): bool
482
+ {
483
+ return is_string($uuid) && Str::isUuid($uuid) && Place::where('uuid', $uuid)->exists();
484
+ }
485
+
486
+ public static function isValidPlacePublicId($publicId): bool
487
+ {
488
+ return is_string($publicId) && Utils::isPublicId($publicId) && Place::where('public_id', $publicId)->exists();
489
+ }
490
+
491
+ /**
492
+ * Inserts a new row into the database and returns the UUID of the inserted row.
493
+ *
494
+ * @param array $values Associative array of values to be inserted
495
+ *
496
+ * @return string|false Returns the UUID of the inserted row if successful, false otherwise
497
+ */
498
+ public static function insertGetUuid($values = [])
499
+ {
500
+ $instance = new static();
501
+ $fillable = $instance->getFillable();
502
+ $insertKeys = array_keys($values);
503
+ // clean insert data
504
+ foreach ($insertKeys as $key) {
505
+ if (!in_array($key, $fillable)) {
506
+ unset($values[$key]);
507
+ }
508
+ }
509
+
510
+ $values['uuid'] = $uuid = static::generateUuid();
511
+ $values['public_id'] = static::generatePublicId('place');
512
+ $values['created_at'] = Carbon::now()->toDateTimeString();
513
+ $values['company_uuid'] = session('company');
514
+ $values['_key'] = session('api_key', 'console');
515
+
516
+ if (isset($values['location'])) {
517
+ $values['location'] = Utils::parsePointToWkt($values['location']);
518
+ }
519
+
520
+ // check if place already exists
521
+ $existing = DB::table($instance->getTable())
522
+ ->select(['uuid'])->where([
523
+ 'company_uuid' => session('company'),
524
+ 'name' => $values['name'] ?? null,
525
+ 'street1' => $values['street1'] ?? null,
526
+ ])
527
+ ->whereNull('deleted_at')
528
+ ->first();
529
+
530
+ if ($existing) {
531
+ unset($values['uuid'], $values['created_at'], $values['_key'], $values['company_uuid']);
532
+ static::where('uuid', $existing->uuid)->update($values);
533
+
534
+ return $existing->uuid;
535
+ }
536
+
537
+ if (isset($values['meta']) && (is_object($values['meta']) || is_array($values['meta']))) {
538
+ $values['meta'] = json_encode($values['meta']);
539
+ }
540
+
541
+ $result = static::insert($values);
542
+
543
+ return $result ? $uuid : false;
544
+ }
545
+
546
+ /**
547
+ * Create a new Place instance from an import row.
548
+ *
549
+ * @param array $row the import row to create a Place from
550
+ * @param int $importId the ID of the import the row is associated with
551
+ * @param string|null $country an optional country to append to the address if it doesn't already contain it
552
+ *
553
+ * @return Place|null the newly created Place instance, or null if no valid address could be found
554
+ */
555
+ public static function createFromImportRow($row, $importId, $country = null): ?Place
556
+ {
557
+ $addressFields = [
558
+ 'street_number' => ['alias' => ['number', 'house_number', 'st_number']],
559
+ 'street2' => ['alias' => ['unit', 'unit_number']],
560
+ 'city' => ['alias' => ['town']],
561
+ 'neighborhood' => ['alias' => ['district']],
562
+ 'province' => ['alias' => ['state']],
563
+ 'postal_code' => ['alias' => ['postal', 'zip', 'zip_code']],
564
+ 'phone' => ['alias' => ['phone', 'mobile', 'phone_number', 'number', 'cell', 'cell_phone', 'mobile_number', 'contact_number']],
565
+ ];
566
+ $address = '';
567
+
568
+ foreach ($addressFields as $field => $options) {
569
+ if ($field === 'phone') {
570
+ continue;
571
+ }
572
+ $value = Utils::or($row, $options['alias']);
573
+ if ($value) {
574
+ $address .= $value . ' ';
575
+ }
576
+ }
577
+
578
+ $address = rtrim($address);
579
+
580
+ if (!$address) {
581
+ return null;
582
+ }
583
+
584
+ $place = Place::createFromGeocodingLookup($address, false);
585
+
586
+ foreach ($addressFields as $field => $options) {
587
+ if (empty($place->{$field})) {
588
+ $value = Utils::or($row, $options['alias']);
589
+ if ($value) {
590
+ $place->{$field} = $value;
591
+ }
592
+ }
593
+ }
594
+
595
+ if ($country && !Str::contains($address, $country)) {
596
+ $address .= ' ' . $country;
597
+ }
598
+
599
+ // set the phone number if found
600
+ $place->phone = Utils::or($row, $addressFields['phone']['alias']);
601
+
602
+ // set meta data
603
+ $meta = collect($row)->except(['name', ...$addressFields['street_number']['alias'], ...$addressFields['street2']['alias'], ...$addressFields['city']['alias'], ...$addressFields['neighborhood']['alias'], ...$addressFields['province']['alias'], ...$addressFields['postal_code']['alias'], ...$addressFields['phone']['alias']])->toArray();
604
+ $place->setMetas($meta);
605
+
606
+ // set the import id
607
+ $place->setAttribute('_import_id', $importId);
608
+
609
+ return $place;
610
+ }
611
+
612
+ /**
613
+ * Returns a formatted string representation of the address for this Place instance.
614
+ *
615
+ * @param array $except an optional array of address components to exclude from the returned string
616
+ * @param bool $useHtml whether to format the returned string as HTML
617
+ *
618
+ * @return string the formatted address string
619
+ */
620
+ public function toAddressString($except = [], $useHtml = false)
621
+ {
622
+ return Utils::getAddressStringForPlace($this, $useHtml, $except);
623
+ }
624
+
625
+ /**
626
+ * Get the full place address as a string.
627
+ *
628
+ * @param bool $useHtml whether to use HTML formatting for the address string
629
+ *
630
+ * @return string the full address as a string
631
+ */
632
+ public function getAddressString($useHtml = false)
633
+ {
634
+ return $this->toAddressString($useHtml);
635
+ }
636
+
637
+ /**
638
+ * Get the vendor's address as an HTML string.
639
+ *
640
+ * @return string the vendor's address as an HTML string
641
+ */
642
+ public function getAddressHtmlAttribute()
643
+ {
644
+ return $this->getAddressString(true);
645
+ }
646
+
647
+ /**
648
+ * Get the vendor's address as a string.
649
+ *
650
+ * @return string the vendor's address as a string
651
+ */
652
+ public function getAddressAttribute()
653
+ {
654
+ return $this->getAddressString();
655
+ }
656
+ }