@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,1132 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Models;
4
+
5
+ use Barryvdh\DomPDF\Facade\Pdf;
6
+ use Fleetbase\Casts\Json;
7
+ use Fleetbase\Casts\PolymorphicType;
8
+ use Fleetbase\FleetOps\Events\OrderCanceled;
9
+ use Fleetbase\FleetOps\Events\OrderCompleted;
10
+ use Fleetbase\FleetOps\Events\OrderDispatched;
11
+ use Fleetbase\FleetOps\Events\OrderDriverAssigned;
12
+ use Fleetbase\FleetOps\Support\Flow;
13
+ use Fleetbase\FleetOps\Support\Utils;
14
+ use Fleetbase\FleetOps\Traits\HasTrackingNumber;
15
+ use Fleetbase\Models\Model;
16
+ use Fleetbase\Models\Transaction;
17
+ use Fleetbase\Traits\HasApiModelBehavior;
18
+ use Fleetbase\Traits\HasInternalId;
19
+ use Fleetbase\Traits\HasMetaAttributes;
20
+ use Fleetbase\Traits\HasOptionsAttributes;
21
+ use Fleetbase\Traits\HasPublicId;
22
+ use Fleetbase\Traits\HasUuid;
23
+ use Fleetbase\Traits\Searchable;
24
+ use Fleetbase\Traits\SendsWebhooks;
25
+ use Fleetbase\Traits\TracksApiCredential;
26
+ use Grimzy\LaravelMysqlSpatial\Types\Point;
27
+ use Illuminate\Support\Carbon;
28
+ use Illuminate\Support\Str;
29
+ use Spatie\Activitylog\Traits\LogsActivity;
30
+
31
+ class Order extends Model
32
+ {
33
+ use HasUuid;
34
+ use HasPublicId;
35
+ use HasInternalId;
36
+ use SendsWebhooks;
37
+ use HasApiModelBehavior;
38
+ use HasOptionsAttributes;
39
+ use HasMetaAttributes;
40
+ use TracksApiCredential;
41
+ use Searchable;
42
+ use LogsActivity;
43
+ use HasTrackingNumber;
44
+
45
+ /**
46
+ * The database table used by the model.
47
+ *
48
+ * @var string
49
+ */
50
+ protected $table = 'orders';
51
+
52
+ /**
53
+ * The type of public Id to generate.
54
+ *
55
+ * @var string
56
+ */
57
+ protected $publicIdType = 'order';
58
+
59
+ /**
60
+ * The attributes that can be queried.
61
+ *
62
+ * @var array
63
+ */
64
+ protected $searchableColumns = ['public_id', 'internal_id', 'trackingNumber.tracking_number', 'meta->storefront', 'meta->storefront_network'];
65
+
66
+ /**
67
+ * The attributes that are mass assignable.
68
+ *
69
+ * @var array
70
+ */
71
+ protected $fillable = [
72
+ '_key',
73
+ 'public_id',
74
+ 'internal_id',
75
+ 'route_uuid',
76
+ 'customer_uuid',
77
+ 'customer_type',
78
+ 'facilitator_uuid',
79
+ 'facilitator_type',
80
+ 'pickup_uuid',
81
+ 'dropoff_uuid',
82
+ 'return_uuid',
83
+ 'company_uuid',
84
+ 'session_uuid',
85
+ 'payload_uuid',
86
+ 'transaction_uuid',
87
+ 'purchase_rate_uuid',
88
+ 'tracking_number_uuid',
89
+ 'driver_assigned_uuid',
90
+ 'created_by_uuid',
91
+ 'updated_by_uuid',
92
+ 'scheduled_at',
93
+ 'dispatched_at',
94
+ 'dispatched',
95
+ 'adhoc',
96
+ 'adhoc_distance',
97
+ 'started',
98
+ 'started_at',
99
+ 'pod_method',
100
+ 'pod_required',
101
+ 'is_route_optimized',
102
+ 'distance',
103
+ 'time',
104
+ 'meta',
105
+ 'notes',
106
+ 'type',
107
+ 'status',
108
+ ];
109
+
110
+ /**
111
+ * Attributes that is filterable on this model.
112
+ *
113
+ * @var array
114
+ */
115
+ protected $filterParams = [
116
+ 'service_quote_uuid',
117
+ 'unassigned',
118
+ 'pod_required',
119
+ 'started',
120
+ 'adhoc',
121
+ 'nearby',
122
+ 'storefront',
123
+ 'unassigned',
124
+ 'active',
125
+ 'tracking',
126
+ 'facilitator',
127
+ 'payload',
128
+ 'pickup',
129
+ 'dropoff',
130
+ 'return',
131
+ 'customer',
132
+ 'driver',
133
+ 'entity_status',
134
+ 'created_by',
135
+ 'updated_by',
136
+ 'layout',
137
+ ];
138
+
139
+ /**
140
+ * Dynamic attributes that are appended to object.
141
+ *
142
+ * @var array
143
+ */
144
+ protected $appends = [
145
+ 'driver_name',
146
+ 'tracking',
147
+ 'total_entities',
148
+ 'transaction_amount',
149
+ 'customer_name',
150
+ 'customer_phone',
151
+ 'facilitator_name',
152
+ 'customer_is_vendor',
153
+ 'customer_is_contact',
154
+ 'facilitator_is_vendor',
155
+ 'facilitator_is_contact',
156
+ 'has_driver_assigned',
157
+ 'pickup_name',
158
+ 'dropoff_name',
159
+ 'payload_id',
160
+ 'purchase_rate_id',
161
+ 'is_scheduled',
162
+ 'qr_code',
163
+ 'created_by_name',
164
+ 'updated_by_name',
165
+ ];
166
+
167
+ /**
168
+ * Relationships to always append to model.
169
+ *
170
+ * @var array
171
+ */
172
+ protected $with = [];
173
+
174
+ /**
175
+ * The attributes that should be cast to native types.
176
+ *
177
+ * @var array
178
+ */
179
+ protected $casts = [
180
+ 'meta' => Json::class,
181
+ 'options' => Json::class,
182
+ 'customer_type' => PolymorphicType::class,
183
+ 'facilitator_type' => PolymorphicType::class,
184
+ 'dispatched' => 'boolean',
185
+ 'adhoc' => 'boolean',
186
+ 'started' => 'boolean',
187
+ 'pod_required' => 'boolean',
188
+ 'scheduled_at' => 'datetime',
189
+ 'dispatched_at' => 'datetime',
190
+ 'started_at' => 'datetime',
191
+ ];
192
+
193
+ /**
194
+ * The attributes excluded from the model's JSON form.
195
+ *
196
+ * @var array
197
+ */
198
+ protected $hidden = [
199
+ 'id',
200
+ '_key',
201
+ ];
202
+
203
+ /**
204
+ * Properties which activity needs to be logged.
205
+ *
206
+ * @var array
207
+ */
208
+ protected static $logAttributes = '*';
209
+
210
+ /**
211
+ * Do not log empty changed.
212
+ *
213
+ * @var bool
214
+ */
215
+ protected static $submitEmptyLogs = false;
216
+
217
+ /**
218
+ * The name of the subject to log.
219
+ *
220
+ * @var string
221
+ */
222
+ protected static $logName = 'order';
223
+
224
+ /**
225
+ * @return \Barryvdh\DomPDF\PDF
226
+ */
227
+ public function pdfLabel()
228
+ {
229
+ return Pdf::loadHTML($this->label());
230
+ }
231
+
232
+ /**
233
+ * @return \Illuminate\Http\Response
234
+ */
235
+ public function pdfLabelStream()
236
+ {
237
+ return $this->pdfLabel()->stream();
238
+ }
239
+
240
+ /**
241
+ * @return \Illuminate\View\View
242
+ */
243
+ public function label()
244
+ {
245
+ $this->load(['trackingNumber', 'company']);
246
+
247
+ return view('fleetops::labels/default', [
248
+ 'order' => $this,
249
+ 'trackingNumber' => $this->trackingNumber,
250
+ 'company' => $this->company,
251
+ ])->render();
252
+ }
253
+
254
+ /**
255
+ * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
256
+ */
257
+ public function transaction()
258
+ {
259
+ return $this->belongsTo(\Fleetbase\Models\Transaction::class);
260
+ }
261
+
262
+ /**
263
+ * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
264
+ */
265
+ public function route()
266
+ {
267
+ return $this->belongsTo(Route::class);
268
+ }
269
+
270
+ /**
271
+ * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
272
+ */
273
+ public function payload()
274
+ {
275
+ return $this->belongsTo(Payload::class)->with(['pickup', 'dropoff', 'return', 'waypoints', 'entities']);
276
+ }
277
+
278
+ /**
279
+ * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
280
+ */
281
+ public function company()
282
+ {
283
+ return $this->belongsTo(\Fleetbase\Models\Company::class);
284
+ }
285
+
286
+ /**
287
+ * @return \Illuminate\Database\Eloquent\Relations\HasOne
288
+ */
289
+ public function orderConfig()
290
+ {
291
+ return $this->hasOne(\Fleetbase\Models\Extension::class, 'key', 'type')->where('type', 'order_config');
292
+ }
293
+
294
+ /**
295
+ * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
296
+ */
297
+ public function createdBy()
298
+ {
299
+ return $this->belongsTo(\Fleetbase\Models\User::class);
300
+ }
301
+
302
+ /**
303
+ * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
304
+ */
305
+ public function updatedBy()
306
+ {
307
+ return $this->belongsTo(\Fleetbase\Models\User::class);
308
+ }
309
+
310
+ /**
311
+ * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
312
+ */
313
+ public function driverAssigned()
314
+ {
315
+ return $this->belongsTo(Driver::class)->without(['devices', 'vehicle', 'vendor'])->withoutGlobalScopes();
316
+ }
317
+
318
+ /**
319
+ * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
320
+ */
321
+ public function driver()
322
+ {
323
+ return $this->belongsTo(Driver::class)->without(['devices', 'vehicle', 'vendor'])->withoutGlobalScopes();
324
+ }
325
+
326
+ /**
327
+ * @return \Illuminate\Database\Eloquent\Relations\HasManyThrough
328
+ */
329
+ public function drivers()
330
+ {
331
+ return $this->hasManyThrough(Driver::class, Entity::class, 'tracking_number_uuid', 'tracking_number_uuid');
332
+ }
333
+
334
+ /**
335
+ * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
336
+ */
337
+ public function trackingNumber()
338
+ {
339
+ return $this->belongsTo(TrackingNumber::class)->without(['owner']);
340
+ }
341
+
342
+ /**
343
+ * @return \Illuminate\Database\Eloquent\Relations\HasMany
344
+ */
345
+ public function trackingStatuses()
346
+ {
347
+ return $this->hasMany(TrackingStatus::class, 'tracking_number_uuid', 'tracking_number_uuid');
348
+ }
349
+
350
+ /**
351
+ * @return \Illuminate\Database\Eloquent\Relations\HasMany
352
+ */
353
+ public function proofs()
354
+ {
355
+ return $this->hasMany(Proof::class, 'subject_uuid');
356
+ }
357
+
358
+ /**
359
+ * @return \Illuminate\Database\Eloquent\Relations\HasMany
360
+ */
361
+ public function purchaseRate()
362
+ {
363
+ return $this->belongsTo(PurchaseRate::class);
364
+ }
365
+
366
+ /**
367
+ * @return \Illuminate\Database\Eloquent\Relations\MorphTo
368
+ */
369
+ public function facilitator()
370
+ {
371
+ return $this->morphTo(__FUNCTION__, 'facilitator_type', 'facilitator_uuid')->withTrashed();
372
+ }
373
+
374
+ /**
375
+ * @return \Illuminate\Database\Eloquent\Relations\MorphTo
376
+ */
377
+ public function customer()
378
+ {
379
+ return $this->morphTo(__FUNCTION__, 'customer_type', 'customer_uuid');
380
+ }
381
+
382
+ /**
383
+ * Get the adhoc distance for this order, or fallback to settings or default value which is 6km.
384
+ *
385
+ * @return int
386
+ */
387
+ public function getAdhocDistance()
388
+ {
389
+ return $this->adhoc_distance ?? data_get($this, 'company.options.fleetops.adhoc_distance', 6000);
390
+ }
391
+
392
+ /**
393
+ * The assigned drivers full name.
394
+ *
395
+ * @return string
396
+ */
397
+ public function getDriverNameAttribute()
398
+ {
399
+ return data_get($this, 'driverAssigned.name');
400
+ }
401
+
402
+ /**
403
+ * The tracking number for the order.
404
+ *
405
+ * @return string
406
+ */
407
+ public function getTrackingAttribute()
408
+ {
409
+ return data_get($this, 'trackingNumber.tracking_number');
410
+ }
411
+
412
+ /**
413
+ * The number of items for this order.
414
+ *
415
+ * @return string
416
+ */
417
+ public function getTotalEntitiesAttribute()
418
+ {
419
+ return (int) $this->fromCache('payload.total_entities');
420
+ }
421
+
422
+ /**
423
+ * The transaction amount for the order.
424
+ *
425
+ * @return string
426
+ */
427
+ public function getTransactionAmountAttribute()
428
+ {
429
+ return data_get($this, 'transaction.amount');
430
+ }
431
+
432
+ /**
433
+ * The customer name for the order.
434
+ *
435
+ * @return string
436
+ */
437
+ public function getCustomerNameAttribute()
438
+ {
439
+ return data_get($this, 'customer.name');
440
+ }
441
+
442
+ /**
443
+ * The customer phone for the order.
444
+ *
445
+ * @return string
446
+ */
447
+ public function getCustomerPhoneAttribute()
448
+ {
449
+ return data_get($this, 'customer.phone');
450
+ }
451
+
452
+ /**
453
+ * The facilitator name for the order.
454
+ *
455
+ * @return string
456
+ */
457
+ public function getFacilitatorNameAttribute()
458
+ {
459
+ return data_get($this, 'facilitator.name');
460
+ }
461
+
462
+ /**
463
+ * True of the facilitator is a vendor `facilitator_is_vendor`.
464
+ *
465
+ * @return bool
466
+ */
467
+ public function getFacilitatorIsVendorAttribute()
468
+ {
469
+ return $this->facilitator_type === 'Fleetbase\\FleetOps\\Models\\Vendor';
470
+ }
471
+
472
+ /**
473
+ * True of the facilitator is a integrated vendor `facilitator_is_integrated_vendor`.
474
+ *
475
+ * @return bool
476
+ */
477
+ public function getFacilitatorIsIntegratedVendorAttribute()
478
+ {
479
+ return $this->facilitator_type === 'Fleetbase\\FleetOps\\Models\\IntegratedVendor';
480
+ }
481
+
482
+ /**
483
+ * True of the facilitator is a contact `facilitator_is_contact`.
484
+ *
485
+ * @return bool
486
+ */
487
+ public function getFacilitatorIsContactAttribute()
488
+ {
489
+ return $this->facilitator_type === 'Fleetbase\\FleetOps\\Models\\Contact';
490
+ }
491
+
492
+ /**
493
+ * True of the customer is a vendor `customer_is_vendor`.
494
+ *
495
+ * @return bool
496
+ */
497
+ public function getCustomerIsVendorAttribute()
498
+ {
499
+ return $this->customer_type === 'Fleetbase\\FleetOps\\Models\\Vendor';
500
+ }
501
+
502
+ /**
503
+ * True of the customer is a contact `customer_is_contact`.
504
+ *
505
+ * @return bool
506
+ */
507
+ public function getCustomerIsContactAttribute()
508
+ {
509
+ return $this->customer_type === 'Fleetbase\\FleetOps\\Models\\Contact';
510
+ }
511
+
512
+ /**
513
+ * The pickup location name.
514
+ */
515
+ public function getPickupNameAttribute()
516
+ {
517
+ return $this->payload ? $this->payload->pickup_name : null;
518
+ }
519
+
520
+ /**
521
+ * The dropoff location name.
522
+ */
523
+ public function getDropoffNameAttribute()
524
+ {
525
+ return $this->payload ? $this->payload->dropoff_name : null;
526
+ }
527
+
528
+ /**
529
+ * The purchase rate public id.
530
+ */
531
+ public function getPurchaseRateIdAttribute()
532
+ {
533
+ return data_get($this, 'purchaseRate.public_id');
534
+ }
535
+
536
+ /**
537
+ * The payload public id.
538
+ */
539
+ public function getPayloadIdAttribute()
540
+ {
541
+ return data_get($this, 'payload.public_id');
542
+ }
543
+
544
+ /**
545
+ * The payload public id.
546
+ *
547
+ * @return string
548
+ */
549
+ public function getQrCodeAttribute()
550
+ {
551
+ return data_get($this, 'trackingNumber.qr_code');
552
+ }
553
+
554
+ /**
555
+ * The name of the user who created the order.
556
+ *
557
+ * @return string
558
+ */
559
+ public function getCreatedByNameAttribute()
560
+ {
561
+ return data_get($this, 'createdBy.name');
562
+ }
563
+
564
+ /**
565
+ * The name of the user who last updated.
566
+ *
567
+ * @return string
568
+ */
569
+ public function getUpdatedByNameAttribute()
570
+ {
571
+ return data_get($this, 'updatedBy.name');
572
+ }
573
+
574
+ /**
575
+ * Set the order type attribute, which defaults to `default`.
576
+ */
577
+ public function setTypeAttribute(string $type = null): void
578
+ {
579
+ $this->attributes['type'] = is_string($type) ? Str::slug($type) : 'default';
580
+ }
581
+
582
+ /**
583
+ * Set the order status attribute, which defaults to `created`.
584
+ */
585
+ public function setStatusAttribute(string $status = null): void
586
+ {
587
+ $this->attributes['status'] = is_string($status) ? Str::snake($status) : 'created';
588
+ }
589
+
590
+ public function getHasDriverAssignedAttribute()
591
+ {
592
+ return (bool) $this->driver_assigned_uuid;
593
+ }
594
+
595
+ public function getIsReadyForDispatchAttribute()
596
+ {
597
+ return $this->hasDrvierAssigned || $this->adhoc;
598
+ }
599
+
600
+ public function getIsScheduledAttribute(): bool
601
+ {
602
+ return !empty($this->scheduled_at) && Carbon::parse($this->scheduled_at)->isValid();
603
+ }
604
+
605
+ public function getIsAssignedNotDispatchedAttribute(): bool
606
+ {
607
+ return !empty($this->driver_assigned_uuid) && !$this->dispatched_at;
608
+ }
609
+
610
+ public function getIsNotDispatchedAttribute(): bool
611
+ {
612
+ return !$this->dispatched_at;
613
+ }
614
+
615
+ public function getIsIntegratedVendorOrderAttribute()
616
+ {
617
+ return $this->isIntegratedVendorOrder();
618
+ }
619
+
620
+ public function setPayload(?Payload $payload): Order
621
+ {
622
+ $this->payload_uuid = $payload->uuid;
623
+ $this->setRelation('payload', $payload);
624
+ $this->save();
625
+
626
+ return $this;
627
+ }
628
+
629
+ public function createPayload(?array $attributes = [], bool $setPayload = true): Payload
630
+ {
631
+ // set payload type if not set
632
+ if (!isset($attributes['type'])) {
633
+ $attributes['type'] = $this->type;
634
+ }
635
+
636
+ if (isset($attributes['pickup']) && is_array($attributes['pickup'])) {
637
+ $pickup = Place::createFromMixed($attributes['pickup']);
638
+
639
+ if ($pickup instanceof Place) {
640
+ $attributes['pickup_uuid'] = $pickup->uuid;
641
+ }
642
+ }
643
+
644
+ if (isset($attributes['dropoff']) && is_array($attributes['dropoff'])) {
645
+ $dropoff = Place::createFromMixed($attributes['dropoff']);
646
+
647
+ if ($dropoff instanceof Place) {
648
+ $attributes['dropoff_uuid'] = $dropoff->uuid;
649
+ }
650
+ }
651
+
652
+ if (isset($attributes['return']) && is_array($attributes['return'])) {
653
+ $return = Place::createFromMixed($attributes['return']);
654
+
655
+ if ($return instanceof Place) {
656
+ $attributes['return_uuid'] = $return->uuid;
657
+ }
658
+ }
659
+
660
+ $payload = Payload::create($attributes);
661
+
662
+ if ($setPayload) {
663
+ $this->setPayload($payload);
664
+ }
665
+
666
+ return $payload;
667
+ }
668
+
669
+ public function insertPayload(?array $attributes = [], bool $setPayload = true): Payload
670
+ {
671
+ // set payload type if not set
672
+ if (!isset($attributes['type'])) {
673
+ $attributes['type'] = $this->type;
674
+ }
675
+
676
+ if (isset($attributes['pickup']) && is_array($attributes['pickup'])) {
677
+ $pickupId = Place::insertFromMixed($attributes['pickup']);
678
+
679
+ $attributes['pickup_uuid'] = $pickupId;
680
+ }
681
+
682
+ if (isset($attributes['dropoff']) && is_array($attributes['dropoff'])) {
683
+ $dropoffId = Place::insertFromMixed($attributes['dropoff']);
684
+
685
+ $attributes['dropoff_uuid'] = $dropoffId;
686
+ }
687
+
688
+ if (isset($attributes['return']) && is_array($attributes['return'])) {
689
+ $returnId = Place::insertFromMixed($attributes['return']);
690
+
691
+ $attributes['return_uuid'] = $returnId;
692
+ }
693
+
694
+ $fillable = $this->getFillable();
695
+ $insertKeys = array_keys($attributes);
696
+ // clean insert data
697
+ foreach ($insertKeys as $key) {
698
+ if (!in_array($key, $fillable)) {
699
+ unset($attributes[$key]);
700
+ }
701
+ }
702
+
703
+ $attributes['uuid'] = $uuid = (string) Str::uuid();
704
+ $attributes['public_id'] = static::generatePublicId('payload');
705
+ $attributes['_key'] = session('api_key', 'console');
706
+ $attributes['created_at'] = Carbon::now()->toDateTimeString();
707
+ $attributes['company_uuid'] = session('company');
708
+
709
+ $result = Payload::insert($attributes);
710
+
711
+ if (!$result) {
712
+ return $this->createPayload($attributes);
713
+ }
714
+
715
+ // get newly inserted payload
716
+ $payload = Payload::find($uuid);
717
+
718
+ // manyally trigger payload created event
719
+ $payload->fireModelEvent('created', false);
720
+
721
+ if ($setPayload) {
722
+ $this->setPayload($payload);
723
+ }
724
+
725
+ return $payload;
726
+ }
727
+
728
+ public function getPayload()
729
+ {
730
+ if ($this->payload) {
731
+ return $this->payload;
732
+ }
733
+
734
+ $this->load('payload');
735
+
736
+ return $this->payload;
737
+ }
738
+
739
+ public function setRoute(?array $attributes = [])
740
+ {
741
+ if (!$attributes) {
742
+ return $this;
743
+ }
744
+
745
+ if ($attributes instanceof Route) {
746
+ $attributes->set('order_uuid', $this->order_uuid);
747
+ $attributes->save();
748
+
749
+ return $this;
750
+ }
751
+
752
+ if (isset($attributes['payload'])) {
753
+ $attributes['details'] = $attributes['payload'];
754
+ unset($attributes['payload']);
755
+ }
756
+
757
+ $attributes['order_uuid'] = $this->uuid;
758
+ $attributes['company_uuid'] = $this->company_uuid ?? session('company');
759
+
760
+ $route = new Route($attributes);
761
+ $route->save();
762
+
763
+ $this->update(['route_uuid' => $route->uuid]);
764
+
765
+ return $this;
766
+ }
767
+
768
+ public function getCurrentDestinationLocation()
769
+ {
770
+ if ($this->payload && $this->payload->dropoff) {
771
+ return $this->payload->dropoff->location;
772
+ }
773
+
774
+ if ($this->payload && $this->payload->waypoints->count() && $this->payload->current_waypoint_uuid) {
775
+ return $this->payload->waypoints->firstWhere('uuid', $this->payload->current_waypoint_uuid)->location;
776
+ }
777
+
778
+ if ($this->payload && $this->payload->waypoints->count()) {
779
+ return $this->payload->waypoints->first()->location;
780
+ }
781
+
782
+ return new Point(0, 0);
783
+ }
784
+
785
+ public function getLastLocation()
786
+ {
787
+ if ($this->driverAssigned && $this->driverAssigned->location) {
788
+ return $this->driverAssigned->location;
789
+ }
790
+
791
+ if ($this->payload && $this->payload->pickup && $this->payload->pickup->location) {
792
+ return $this->payload->pickup->location;
793
+ }
794
+
795
+ if ($this->payload && $this->payload->waypoints->count() && $this->payload->current_waypoint_uuid) {
796
+ return $this->payload->waypoints->firstWhere('uuid', $this->payload->current_waypoint_uuid)->location;
797
+ }
798
+
799
+ if ($this->payload && $this->payload->waypoints->count()) {
800
+ return $this->payload->waypoints->first()->location;
801
+ }
802
+
803
+ return new Point(0, 0);
804
+ }
805
+
806
+ public function purchaseQuote(string $serviceQuoteId, $meta = [])
807
+ {
808
+ // $serviceQuote = ServiceQuote::where('uuid', $serviceQuoteId)->first();
809
+ // create purchase rate for order
810
+ $purchasedRate = PurchaseRate::create([
811
+ 'customer_uuid' => $this->customer_uuid,
812
+ 'customer_type' => $this->customer_type,
813
+ 'company_uuid' => session('company'),
814
+ 'service_quote_uuid' => $serviceQuoteId,
815
+ 'payload_uuid' => $this->payload_uuid,
816
+ 'status' => 'created',
817
+ 'meta' => $meta,
818
+ ]);
819
+
820
+ $this->purchase_rate_uuid = $purchasedRate->uuid;
821
+
822
+ return $this->save();
823
+ }
824
+
825
+ public function purchaseServiceQuote($serviceQuote, $meta = [])
826
+ {
827
+ if (!$serviceQuote) {
828
+ // create transaction for order
829
+ $this->createOrderTransactionWithoutServiceQuote();
830
+
831
+ return $this;
832
+ }
833
+
834
+ if (Str::isUuid($serviceQuote)) {
835
+ $serviceQuote = ServiceQuote::where('uuid', $serviceQuote)->first();
836
+ }
837
+
838
+ if (Utils::isPublicId($serviceQuote)) {
839
+ $serviceQuote = ServiceQuote::where('public_id', $serviceQuote)->first();
840
+ }
841
+
842
+ if ($serviceQuote instanceof ServiceQuote) {
843
+ $purchasedRate = PurchaseRate::create([
844
+ 'customer_uuid' => $this->customer_uuid,
845
+ 'customer_type' => $this->customer_type,
846
+ 'company_uuid' => $this->company_uuid ?? session('company'),
847
+ 'service_quote_uuid' => $serviceQuote->uuid,
848
+ 'payload_uuid' => $this->payload_uuid,
849
+ 'status' => 'created',
850
+ 'meta' => $meta,
851
+ ]);
852
+
853
+ return $this->update([
854
+ 'purchase_rate_uuid' => $purchasedRate->uuid,
855
+ ]);
856
+ }
857
+
858
+ return false;
859
+ }
860
+
861
+ public function createOrderTransactionWithoutServiceQuote(): ?Transaction
862
+ {
863
+ $transaction = null;
864
+
865
+ try {
866
+ // create transaction and transaction items
867
+ $transaction = Transaction::create([
868
+ 'company_uuid' => session('company', $this->company_uuid),
869
+ 'customer_uuid' => $this->customer_uuid,
870
+ 'customer_type' => $this->customer_type,
871
+ 'gateway_transaction_id' => Transaction::generateNumber(),
872
+ 'gateway' => 'internal',
873
+ 'amount' => 0,
874
+ 'currency' => data_get($this->company, 'country') ? Utils::getCurrenyFromCountryCode(data_get($this->company, 'country')) : 'SGD',
875
+ 'description' => 'Dispatch order',
876
+ 'type' => 'dispatch',
877
+ 'status' => 'success',
878
+ ]);
879
+
880
+ // set transaction to order
881
+ $this->update(['transaction_uuid' => $transaction->uuid]);
882
+ } catch (\Throwable $e) {
883
+ // log error unable to create order transaction
884
+ }
885
+
886
+ return $transaction;
887
+ }
888
+
889
+ public function shouldDispatch($precision = 1)
890
+ {
891
+ $min = Carbon::now()->subMinutes($precision);
892
+ $max = Carbon::now()->addMinutes($precision);
893
+
894
+ return !$this->dispatched && Carbon::fromString($this->scheduled_at)->between($min, $max);
895
+ }
896
+
897
+ public function dispatch($save = false)
898
+ {
899
+ $this->dispatched = true;
900
+ $this->dispatched_at = now();
901
+
902
+ if ($save === true) {
903
+ $this->save();
904
+ $this->flushAttributesCache();
905
+ }
906
+
907
+ return event(new OrderDispatched($this));
908
+ }
909
+
910
+ public function firstDispatch()
911
+ {
912
+ if ($this->dispatched) {
913
+ $this->dispatch();
914
+ }
915
+ }
916
+
917
+ public function cancel()
918
+ {
919
+ $this->status = 'canceled';
920
+
921
+ if ($this->isIntegratedVendorOrder()) {
922
+ $api = $this->facilitator->api();
923
+
924
+ if (method_exists($api, 'cancelFromFleetbaseOrder')) {
925
+ $api->cancelFromFleetbaseOrder($this);
926
+ }
927
+ }
928
+
929
+ return event(new OrderCanceled($this));
930
+ }
931
+
932
+ public function notifyDriverAssigned()
933
+ {
934
+ if ($this->driver_assigned_uuid) {
935
+ return event(new OrderDriverAssigned($this));
936
+ }
937
+ }
938
+
939
+ public function notifyCompleted()
940
+ {
941
+ return event(new OrderCompleted($this));
942
+ }
943
+
944
+ public function setCustomer($model)
945
+ {
946
+ $this->customer_uuid = $model->uuid;
947
+ $this->customer_type = Utils::getModelClassName($model);
948
+ }
949
+
950
+ public function setDriverLocationAsPickup($force = false)
951
+ {
952
+ if ($force === true) {
953
+ $this->load('driverAssigned');
954
+
955
+ if ($this->driverAssigned instanceof Driver) {
956
+ $this->payload->setPickup($this->driverAssigned->location, true);
957
+ }
958
+ }
959
+
960
+ // if payload is using a special key `pickup_is_driver_location`
961
+ // and driver is assigned set the pickup point as the drivers current location
962
+ if ($this->isDirty('driver_assigned_uuid') && !empty($this->driver_assigned_uuid) && $this->payload && $this->payload->hasMeta('pickup_is_driver_location')) {
963
+ $this->load('driverAssigned');
964
+
965
+ if ($this->driverAssigned instanceof Driver) {
966
+ $this->payload->setPickup($this->driverAssigned->location, true);
967
+ }
968
+ }
969
+ }
970
+
971
+ public function isPickupIsFromDriverLocation()
972
+ {
973
+ return $this->payload instanceof Payload && $this->payload->hasMeta('pickup_is_driver_location');
974
+ }
975
+
976
+ public function updateStatus($code = null)
977
+ {
978
+ // update multiple status codes
979
+ if (is_array($code)) {
980
+ return collect($code)->every(function ($activityCode) {
981
+ return $this->updateStatus($activityCode);
982
+ });
983
+ }
984
+
985
+ $flow = Flow::getOrderFlow($this);
986
+ $activity = null;
987
+
988
+ if (count($flow) === 1 && $code === null) {
989
+ $activity = $flow[0];
990
+ }
991
+
992
+ if ($code) {
993
+ $activity = collect($flow)->firstWhere('code', $code);
994
+ }
995
+
996
+ if (!$activity) {
997
+ return false;
998
+ }
999
+
1000
+ $isDispatchActivity = is_array($activity) && $activity['code'] === 'dispatched';
1001
+ $isReadyForDispatch = $this->isReadyForDispatch;
1002
+
1003
+ if ($isDispatchActivity && $isReadyForDispatch) {
1004
+ $this->dispatch(true);
1005
+ }
1006
+
1007
+ // edge case if not dispatched but code is dispatched/dispatch
1008
+ if (!$this->dispatched && Str::startsWith($code, 'dispatch')) {
1009
+ $this->dispatch(true);
1010
+ }
1011
+
1012
+ $location = $this->getLastLocation();
1013
+
1014
+ $this->setStatus($activity['code']);
1015
+ $this->insertActivity($activity['status'], $activity['details'], $location, $activity['code']);
1016
+
1017
+ return true;
1018
+ }
1019
+
1020
+ public function isDriver($driver)
1021
+ {
1022
+ if ($driver instanceof Driver) {
1023
+ return $driver->uuid === $this->driver_assigned_uuid;
1024
+ }
1025
+
1026
+ if (is_string($driver)) {
1027
+ return $driver === $this->driver_assigned_uuid || ($this->driverAssigned && $driver === $this->driverAssigned->public_id);
1028
+ }
1029
+
1030
+ return $driver === $this->driverAssigned;
1031
+ }
1032
+
1033
+ public function assignDriver($driver, $silent = false)
1034
+ {
1035
+ if ($driver instanceof Driver) {
1036
+ $this->driver_assigned_uuid = $driver->uuid;
1037
+ }
1038
+
1039
+ if (is_string($driver)) {
1040
+ if (Str::startsWith($driver, 'driver_')) {
1041
+ $driver = Driver::select(['uuid', 'public_id'])->where('public_id', $driver)->whereNull('deleted_at')->withoutGlobalScopes()->first();
1042
+ if ($driver) {
1043
+ return $this->assignDriver($driver);
1044
+ }
1045
+
1046
+ throw new \Exception('Invalid driver provided for assignment!');
1047
+ }
1048
+
1049
+ $this->driver_assigned_uuid = $driver;
1050
+ }
1051
+
1052
+ if ($driver instanceof Driver) {
1053
+ $this->setRelation('driverAssigned', $driver);
1054
+ }
1055
+
1056
+ if (!$silent) {
1057
+ $this->notifyDriverAssigned();
1058
+ }
1059
+
1060
+ $this->save();
1061
+
1062
+ return $this;
1063
+ }
1064
+
1065
+ public function getCurrentOriginPosition()
1066
+ {
1067
+ if ($this->hasDriverAssigned) {
1068
+ return $this->driverAssigned->location;
1069
+ }
1070
+
1071
+ $origin = null;
1072
+
1073
+ if ($this->payload) {
1074
+ $origin = $this->payload->getPickupOrCurrentWaypoint();
1075
+ }
1076
+
1077
+ return $origin ? $origin->location : null;
1078
+ }
1079
+
1080
+ public function getDestinationPosition()
1081
+ {
1082
+ $destination = null;
1083
+
1084
+ if ($this->payload) {
1085
+ $destination = $this->payload->getDropoffOrLastWaypoint();
1086
+ }
1087
+
1088
+ return $destination ? $destination->location : null;
1089
+ }
1090
+
1091
+ public function setPreliminaryDistanceAndTime()
1092
+ {
1093
+ $origin = $this->getCurrentOriginPosition();
1094
+ $destination = $this->getDestinationPosition();
1095
+
1096
+ if ($origin === null || $destination === null) {
1097
+ return $this;
1098
+ }
1099
+
1100
+ $matrix = Utils::getPreliminaryDistanceMatrix($origin, $destination);
1101
+
1102
+ $this->update(['distance' => $matrix->distance, 'time' => $matrix->time]);
1103
+
1104
+ return $this;
1105
+ }
1106
+
1107
+ public function setDistanceAndTime(): Order
1108
+ {
1109
+ $origin = $this->getCurrentOriginPosition();
1110
+ $destination = $this->getDestinationPosition();
1111
+
1112
+ $matrix = Utils::getDrivingDistanceAndTime($origin, $destination);
1113
+
1114
+ if ($origin === null || $destination === null) {
1115
+ return $this;
1116
+ }
1117
+
1118
+ $this->update(['distance' => $matrix->distance, 'time' => $matrix->time]);
1119
+
1120
+ return $this;
1121
+ }
1122
+
1123
+ public function isIntegratedVendorOrder()
1124
+ {
1125
+ return $this->facilitator_is_integrated_vendor === true;
1126
+ }
1127
+
1128
+ public function getAdhocPingDistance(): int
1129
+ {
1130
+ return (int) Utils::get($this, 'adhoc_distance', Utils::get($this, 'company.options.fleetops.adhoc_distance', 6000));
1131
+ }
1132
+ }