@fleetbase/storefront-engine 0.1.6 → 0.1.8

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 (333) hide show
  1. package/.php-cs-fixer.php +29 -0
  2. package/LICENSE.md +16 -4
  3. package/README.md +106 -13
  4. package/addon/components/modals/add-store-to-category.hbs +5 -0
  5. package/addon/components/modals/create-network-category.hbs +28 -28
  6. package/addon/components/modals/share-network.hbs +3 -3
  7. package/addon/components/modals/store-details.hbs +22 -0
  8. package/addon/components/modals/store-form.hbs +22 -0
  9. package/addon/components/modals/store-form.js +21 -0
  10. package/addon/components/network-category-picker.hbs +40 -0
  11. package/addon/components/network-category-picker.js +83 -0
  12. package/addon/components/store-selector.hbs +4 -2
  13. package/addon/components/widget/orders.js +22 -17
  14. package/addon/controllers/networks/index/network/index.js +133 -9
  15. package/addon/controllers/networks/index/network/stores.js +422 -153
  16. package/addon/controllers/networks/index.js +66 -4
  17. package/addon/controllers/products/index/category.js +1 -1
  18. package/addon/controllers/settings/index.js +14 -7
  19. package/addon/controllers/settings/notifications.js +1 -1
  20. package/addon/models/store.js +44 -7
  21. package/addon/routes/networks/index/network/customers.js +4 -1
  22. package/addon/routes/networks/index/network/orders.js +4 -1
  23. package/addon/routes/networks/index/network/stores.js +19 -15
  24. package/addon/serializers/store.js +1 -0
  25. package/addon/templates/customers/index.hbs +0 -11
  26. package/addon/templates/networks/index/network/index.hbs +1 -1
  27. package/addon/templates/networks/index/network/stores.hbs +8 -163
  28. package/addon/templates/networks/index/network.hbs +2 -3
  29. package/addon/utils/create-shareable-link.js +21 -0
  30. package/app/adapters/addon-category.js +1 -1
  31. package/app/adapters/gateway.js +1 -1
  32. package/app/adapters/network.js +1 -1
  33. package/app/adapters/notification-channel.js +1 -1
  34. package/app/adapters/product-addon-category.js +1 -1
  35. package/app/adapters/product-addon.js +1 -1
  36. package/app/adapters/product-hour.js +1 -1
  37. package/app/adapters/product-store-location.js +1 -1
  38. package/app/adapters/product-variant-option.js +1 -1
  39. package/app/adapters/product-variant.js +1 -1
  40. package/app/adapters/product.js +1 -1
  41. package/app/adapters/store-hour.js +1 -1
  42. package/app/adapters/store-location.js +1 -1
  43. package/app/adapters/store.js +1 -1
  44. package/app/adapters/storefront.js +1 -1
  45. package/app/components/file-record.js +1 -1
  46. package/app/components/modals/add-store-hours.js +1 -1
  47. package/app/components/modals/add-store-to-category.js +1 -0
  48. package/app/components/modals/add-stores-to-network.js +1 -1
  49. package/app/components/modals/assign-driver.js +1 -1
  50. package/app/components/modals/create-first-store.js +1 -1
  51. package/app/components/modals/create-gateway.js +1 -1
  52. package/app/components/modals/create-network-category.js +1 -1
  53. package/app/components/modals/create-network.js +1 -1
  54. package/app/components/modals/create-new-variant.js +1 -1
  55. package/app/components/modals/create-notification-channel.js +1 -1
  56. package/app/components/modals/create-product-category.js +1 -1
  57. package/app/components/modals/create-store.js +1 -1
  58. package/app/components/modals/edit-network.js +1 -1
  59. package/app/components/modals/import-products.js +1 -1
  60. package/app/components/modals/incoming-order.js +1 -1
  61. package/app/components/modals/manage-addons.js +1 -1
  62. package/app/components/modals/order-ready-assign-driver.js +1 -1
  63. package/app/components/modals/select-addon-category.js +1 -1
  64. package/app/components/modals/share-network.js +1 -1
  65. package/app/components/modals/store-details.js +1 -0
  66. package/app/components/modals/store-form.js +1 -0
  67. package/app/components/modals/store-location-form.js +1 -1
  68. package/app/components/network-category-picker.js +1 -0
  69. package/app/components/order-card.js +1 -1
  70. package/app/components/schedule-manager.js +1 -1
  71. package/app/components/settings-container.js +1 -1
  72. package/app/components/store-selector.js +1 -1
  73. package/app/components/widget/customers.js +1 -1
  74. package/app/components/widget/orders.js +1 -1
  75. package/app/components/widget/storefront-metrics.js +1 -1
  76. package/app/controllers/application.js +1 -1
  77. package/app/controllers/customers/index.js +1 -1
  78. package/app/controllers/home.js +1 -1
  79. package/app/controllers/networks/index/network/customers.js +1 -1
  80. package/app/controllers/networks/index/network/index.js +1 -1
  81. package/app/controllers/networks/index/network/orders.js +1 -1
  82. package/app/controllers/networks/index/network/stores.js +1 -1
  83. package/app/controllers/networks/index/network.js +1 -1
  84. package/app/controllers/networks/index.js +1 -1
  85. package/app/controllers/orders/index.js +1 -1
  86. package/app/controllers/products/index/category/edit.js +1 -1
  87. package/app/controllers/products/index/category/new.js +1 -1
  88. package/app/controllers/products/index/category.js +1 -1
  89. package/app/controllers/products/index/index/edit.js +1 -1
  90. package/app/controllers/products/index/index.js +1 -1
  91. package/app/controllers/products/index.js +1 -1
  92. package/app/controllers/settings/api.js +1 -1
  93. package/app/controllers/settings/gateways.js +1 -1
  94. package/app/controllers/settings/index.js +1 -1
  95. package/app/controllers/settings/locations.js +1 -1
  96. package/app/controllers/settings/notifications.js +1 -1
  97. package/app/helpers/get-tip-amount.js +1 -1
  98. package/app/models/addon-category.js +1 -1
  99. package/app/models/gateway.js +1 -1
  100. package/app/models/network.js +1 -1
  101. package/app/models/notification-channel.js +1 -1
  102. package/app/models/product-addon-category.js +1 -1
  103. package/app/models/product-addon.js +1 -1
  104. package/app/models/product-hour.js +1 -1
  105. package/app/models/product-store-location.js +1 -1
  106. package/app/models/product-variant-option.js +1 -1
  107. package/app/models/product-variant.js +1 -1
  108. package/app/models/product.js +1 -1
  109. package/app/models/store-hour.js +1 -1
  110. package/app/models/store-location.js +1 -1
  111. package/app/models/store.js +1 -1
  112. package/app/routes/application.js +1 -1
  113. package/app/routes/customers/index/edit.js +1 -1
  114. package/app/routes/customers/index.js +1 -1
  115. package/app/routes/home.js +1 -1
  116. package/app/routes/networks/index/network/customers.js +1 -1
  117. package/app/routes/networks/index/network/index.js +1 -1
  118. package/app/routes/networks/index/network/orders.js +1 -1
  119. package/app/routes/networks/index/network/stores.js +1 -1
  120. package/app/routes/networks/index/network.js +1 -1
  121. package/app/routes/networks/index.js +1 -1
  122. package/app/routes/orders/index/edit.js +1 -1
  123. package/app/routes/orders/index/new.js +1 -1
  124. package/app/routes/orders/index/view.js +1 -1
  125. package/app/routes/orders/index.js +1 -1
  126. package/app/routes/products/index/category/edit.js +1 -1
  127. package/app/routes/products/index/category/new.js +1 -1
  128. package/app/routes/products/index/category.js +1 -1
  129. package/app/routes/products/index/index/edit.js +1 -1
  130. package/app/routes/products/index/index.js +1 -1
  131. package/app/routes/products/index.js +1 -1
  132. package/app/routes/settings/api.js +1 -1
  133. package/app/routes/settings/gateways.js +1 -1
  134. package/app/routes/settings/index.js +1 -1
  135. package/app/routes/settings/locations.js +1 -1
  136. package/app/routes/settings/notifications.js +1 -1
  137. package/app/serializers/addon-category.js +1 -1
  138. package/app/serializers/network.js +1 -1
  139. package/app/serializers/notification-channel.js +1 -1
  140. package/app/serializers/product-addon-category.js +1 -1
  141. package/app/serializers/product-variant.js +1 -1
  142. package/app/serializers/product.js +1 -1
  143. package/app/serializers/store-location.js +1 -1
  144. package/app/serializers/store.js +1 -1
  145. package/app/services/storefront.js +1 -1
  146. package/app/templates/customers/index/edit.js +1 -1
  147. package/app/templates/customers/index.js +1 -1
  148. package/app/templates/home.js +1 -1
  149. package/app/templates/networks/index/network/customers.js +1 -1
  150. package/app/templates/networks/index/network/index.js +1 -1
  151. package/app/templates/networks/index/network/orders.js +1 -1
  152. package/app/templates/networks/index/network/stores.js +1 -1
  153. package/app/templates/networks/index/network.js +1 -1
  154. package/app/templates/networks/index.js +1 -1
  155. package/app/templates/orders/index/edit.js +1 -1
  156. package/app/templates/orders/index/new.js +1 -1
  157. package/app/templates/orders/index/view.js +1 -1
  158. package/app/templates/orders/index.js +1 -1
  159. package/app/templates/products/index/category/edit.js +1 -1
  160. package/app/templates/products/index/category/new.js +1 -1
  161. package/app/templates/products/index/category.js +1 -1
  162. package/app/templates/products/index/index/edit.js +1 -1
  163. package/app/templates/products/index/index.js +1 -1
  164. package/app/templates/products/index.js +1 -1
  165. package/app/templates/settings/api.js +1 -1
  166. package/app/templates/settings/gateways.js +1 -1
  167. package/app/templates/settings/index.js +1 -1
  168. package/app/templates/settings/locations.js +1 -1
  169. package/app/templates/settings/notifications.js +1 -1
  170. package/app/templates/settings.js +1 -1
  171. package/app/utils/create-shareable-link.js +1 -0
  172. package/app/utils/get-gateway-schemas.js +1 -1
  173. package/app/utils/get-notification-schemas.js +1 -1
  174. package/composer.json +88 -0
  175. package/extension.json +10 -0
  176. package/package.json +6 -7
  177. package/phpstan.neon.dist +8 -0
  178. package/phpunit.xml.dist +16 -0
  179. package/server/.gitattributes +14 -0
  180. package/server/README.md +40 -0
  181. package/server/config/api.php +101 -0
  182. package/server/config/database.connections.php +57 -0
  183. package/server/config/storefront.php +19 -0
  184. package/server/config/twilio-notification-channel.php +36 -0
  185. package/server/migrations/2023_05_03_025307_create_carts_table.php +44 -0
  186. package/server/migrations/2023_05_03_025307_create_checkouts_table.php +51 -0
  187. package/server/migrations/2023_05_03_025307_create_gateways_table.php +48 -0
  188. package/server/migrations/2023_05_03_025307_create_network_stores_table.php +36 -0
  189. package/server/migrations/2023_05_03_025307_create_networks_table.php +56 -0
  190. package/server/migrations/2023_05_03_025307_create_notification_channels_table.php +43 -0
  191. package/server/migrations/2023_05_03_025307_create_payment_methods_table.php +44 -0
  192. package/server/migrations/2023_05_03_025307_create_product_addon_categories_table.php +38 -0
  193. package/server/migrations/2023_05_03_025307_create_product_addons_table.php +43 -0
  194. package/server/migrations/2023_05_03_025307_create_product_hours_table.php +37 -0
  195. package/server/migrations/2023_05_03_025307_create_product_store_locations_table.php +34 -0
  196. package/server/migrations/2023_05_03_025307_create_product_variant_options_table.php +40 -0
  197. package/server/migrations/2023_05_03_025307_create_product_variants_table.php +44 -0
  198. package/server/migrations/2023_05_03_025307_create_products_table.php +59 -0
  199. package/server/migrations/2023_05_03_025307_create_reviews_table.php +41 -0
  200. package/server/migrations/2023_05_03_025307_create_store_hours_table.php +37 -0
  201. package/server/migrations/2023_05_03_025307_create_store_locations_table.php +38 -0
  202. package/server/migrations/2023_05_03_025307_create_stores_table.php +57 -0
  203. package/server/migrations/2023_05_03_025307_create_votes_table.php +39 -0
  204. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_carts_table.php +40 -0
  205. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_checkouts_table.php +48 -0
  206. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_gateways_table.php +40 -0
  207. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_network_stores_table.php +40 -0
  208. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_networks_table.php +42 -0
  209. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_notification_channels_table.php +40 -0
  210. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_payment_methods_table.php +40 -0
  211. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_addon_categories_table.php +38 -0
  212. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_addons_table.php +38 -0
  213. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_hours_table.php +32 -0
  214. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_store_locations_table.php +34 -0
  215. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_variant_options_table.php +32 -0
  216. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_variants_table.php +32 -0
  217. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_products_table.php +44 -0
  218. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_reviews_table.php +38 -0
  219. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_store_hours_table.php +32 -0
  220. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_store_locations_table.php +40 -0
  221. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_stores_table.php +42 -0
  222. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_votes_table.php +38 -0
  223. package/server/src/Auth/Schemas/Storefront.php +95 -0
  224. package/server/src/Console/Commands/NotifyStorefrontOrderNearby.php +86 -0
  225. package/server/src/Expansions/EntityExpansion.php +44 -0
  226. package/server/src/Http/Controllers/ActionController.php +119 -0
  227. package/server/src/Http/Controllers/AddonCategoryController.php +13 -0
  228. package/server/src/Http/Controllers/CustomerController.php +13 -0
  229. package/server/src/Http/Controllers/GatewayController.php +13 -0
  230. package/server/src/Http/Controllers/MetricsController.php +71 -0
  231. package/server/src/Http/Controllers/NetworkController.php +170 -0
  232. package/server/src/Http/Controllers/NotificationChannelController.php +13 -0
  233. package/server/src/Http/Controllers/OrderController.php +154 -0
  234. package/server/src/Http/Controllers/ProductAddonCategoryController.php +14 -0
  235. package/server/src/Http/Controllers/ProductAddonController.php +14 -0
  236. package/server/src/Http/Controllers/ProductController.php +123 -0
  237. package/server/src/Http/Controllers/ProductHourController.php +13 -0
  238. package/server/src/Http/Controllers/ProductVariantController.php +13 -0
  239. package/server/src/Http/Controllers/ProductVariantOptionController.php +13 -0
  240. package/server/src/Http/Controllers/ReviewController.php +13 -0
  241. package/server/src/Http/Controllers/StoreController.php +26 -0
  242. package/server/src/Http/Controllers/StoreHourController.php +13 -0
  243. package/server/src/Http/Controllers/StoreLocationController.php +13 -0
  244. package/server/src/Http/Controllers/StorefrontController.php +15 -0
  245. package/server/src/Http/Controllers/VoteController.php +13 -0
  246. package/server/src/Http/Controllers/v1/CartController.php +161 -0
  247. package/server/src/Http/Controllers/v1/CategoryController.php +138 -0
  248. package/server/src/Http/Controllers/v1/CheckoutController.php +957 -0
  249. package/server/src/Http/Controllers/v1/CustomerController.php +482 -0
  250. package/server/src/Http/Controllers/v1/GatewayControllerController.php +11 -0
  251. package/server/src/Http/Controllers/v1/NetworkController.php +281 -0
  252. package/server/src/Http/Controllers/v1/PaymentMethodController.php +11 -0
  253. package/server/src/Http/Controllers/v1/ProductController.php +94 -0
  254. package/server/src/Http/Controllers/v1/ReviewController.php +270 -0
  255. package/server/src/Http/Controllers/v1/ServiceQuoteController.php +402 -0
  256. package/server/src/Http/Controllers/v1/StoreController.php +176 -0
  257. package/server/src/Http/Filter/AddonCategoryFilter.php +19 -0
  258. package/server/src/Http/Filter/CustomerFilter.php +18 -0
  259. package/server/src/Http/Filter/GatewayFilter.php +13 -0
  260. package/server/src/Http/Filter/NetworkFilter.php +18 -0
  261. package/server/src/Http/Filter/NotificationChannelFilter.php +13 -0
  262. package/server/src/Http/Filter/OrderFilter.php +46 -0
  263. package/server/src/Http/Filter/ProductFilter.php +28 -0
  264. package/server/src/Http/Filter/StoreFilter.php +42 -0
  265. package/server/src/Http/Filter/StoreLocationFilter.php +23 -0
  266. package/server/src/Http/Middleware/SetStorefrontSession.php +130 -0
  267. package/server/src/Http/Requests/AddStoreToNetworkCategory.php +45 -0
  268. package/server/src/Http/Requests/CaptureOrderRequest.php +30 -0
  269. package/server/src/Http/Requests/CreateCustomerRequest.php +44 -0
  270. package/server/src/Http/Requests/CreateReviewRequest.php +34 -0
  271. package/server/src/Http/Requests/GetServiceQuoteFromCart.php +40 -0
  272. package/server/src/Http/Requests/InitializeCheckoutRequest.php +38 -0
  273. package/server/src/Http/Requests/NetworkActionRequest.php +43 -0
  274. package/server/src/Http/Requests/VerifyCreateCustomerRequest.php +31 -0
  275. package/server/src/Http/Resources/Cart.php +31 -0
  276. package/server/src/Http/Resources/Category.php +48 -0
  277. package/server/src/Http/Resources/Customer.php +36 -0
  278. package/server/src/Http/Resources/Gateway.php +32 -0
  279. package/server/src/Http/Resources/Media.php +29 -0
  280. package/server/src/Http/Resources/Network.php +48 -0
  281. package/server/src/Http/Resources/Product.php +209 -0
  282. package/server/src/Http/Resources/Review.php +45 -0
  283. package/server/src/Http/Resources/ReviewCustomer.php +60 -0
  284. package/server/src/Http/Resources/Store.php +76 -0
  285. package/server/src/Http/Resources/StoreHour.php +29 -0
  286. package/server/src/Http/Resources/StoreLocation.php +33 -0
  287. package/server/src/Imports/ProductsImport.php +20 -0
  288. package/server/src/Jobs/DownloadProductImageUrl.php +60 -0
  289. package/server/src/Listeners/HandleOrderCompleted.php +31 -0
  290. package/server/src/Listeners/HandleOrderDispatched.php +34 -0
  291. package/server/src/Listeners/HandleOrderDriverAssigned.php +37 -0
  292. package/server/src/Listeners/HandleOrderStarted.php +27 -0
  293. package/server/src/Mail/StorefrontNetworkInvite.php +48 -0
  294. package/server/src/Models/AddonCategory.php +30 -0
  295. package/server/src/Models/Cart.php +691 -0
  296. package/server/src/Models/Checkout.php +166 -0
  297. package/server/src/Models/Customer.php +88 -0
  298. package/server/src/Models/Gateway.php +165 -0
  299. package/server/src/Models/Network.php +300 -0
  300. package/server/src/Models/NetworkStore.php +86 -0
  301. package/server/src/Models/NotificationChannel.php +147 -0
  302. package/server/src/Models/PaymentMethod.php +99 -0
  303. package/server/src/Models/Product.php +315 -0
  304. package/server/src/Models/ProductAddon.php +128 -0
  305. package/server/src/Models/ProductAddonCategory.php +90 -0
  306. package/server/src/Models/ProductHour.php +59 -0
  307. package/server/src/Models/ProductStoreLocation.php +77 -0
  308. package/server/src/Models/ProductVariant.php +125 -0
  309. package/server/src/Models/ProductVariantOption.php +86 -0
  310. package/server/src/Models/Review.php +127 -0
  311. package/server/src/Models/Store.php +478 -0
  312. package/server/src/Models/StoreHour.php +59 -0
  313. package/server/src/Models/StoreLocation.php +126 -0
  314. package/server/src/Models/StorefrontModel.php +22 -0
  315. package/server/src/Models/Vote.php +84 -0
  316. package/server/src/Notifications/StorefrontOrderCanceled.php +196 -0
  317. package/server/src/Notifications/StorefrontOrderCompleted.php +201 -0
  318. package/server/src/Notifications/StorefrontOrderCreated.php +157 -0
  319. package/server/src/Notifications/StorefrontOrderDriverAssigned.php +200 -0
  320. package/server/src/Notifications/StorefrontOrderEnroute.php +199 -0
  321. package/server/src/Notifications/StorefrontOrderNearby.php +201 -0
  322. package/server/src/Notifications/StorefrontOrderPreparing.php +202 -0
  323. package/server/src/Notifications/StorefrontOrderReadyForPickup.php +202 -0
  324. package/server/src/Observers/NetworkObserver.php +40 -0
  325. package/server/src/Observers/ProductObserver.php +118 -0
  326. package/server/src/Providers/EventServiceProvider.php +23 -0
  327. package/server/src/Providers/StorefrontServiceProvider.php +103 -0
  328. package/server/src/Support/Metrics.php +193 -0
  329. package/server/src/Support/OrderConfig.php +13 -0
  330. package/server/src/Support/QPay.php +208 -0
  331. package/server/src/Support/Storefront.php +201 -0
  332. package/server/src/routes.php +180 -0
  333. package/server/tests/Feature.php +5 -0
@@ -0,0 +1,402 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\Storefront\Http\Controllers\v1;
4
+
5
+ use Fleetbase\Http\Controllers\Controller;
6
+ use Fleetbase\Storefront\Http\Requests\GetServiceQuoteFromCart;
7
+ use Fleetbase\FleetOps\Http\Resources\v1\ServiceQuote as ServiceQuoteResource;
8
+ use Fleetbase\FleetOps\Models\Entity;
9
+ use Fleetbase\FleetOps\Models\Place;
10
+ use Fleetbase\FleetOps\Models\ServiceQuote;
11
+ use Fleetbase\FleetOps\Models\ServiceQuoteItem;
12
+ use Fleetbase\FleetOps\Models\ServiceRate;
13
+ use Fleetbase\FleetOps\Models\IntegratedVendor;
14
+ use Fleetbase\Storefront\Models\Store;
15
+ use Fleetbase\Storefront\Models\Cart;
16
+ use Fleetbase\Storefront\Models\Product;
17
+ use Fleetbase\Storefront\Models\StoreLocation;
18
+ use Fleetbase\FleetOps\Support\Flow;
19
+ use Fleetbase\FleetOps\Support\Utils;
20
+ use Illuminate\Support\Str;
21
+
22
+ class ServiceQuoteController extends Controller
23
+ {
24
+ /**
25
+ * Query for Storefront Product resources.
26
+ *
27
+ * @param \Illuminate\Http\Request $request
28
+ * @return \Fleetbase\Http\Resources\DriverCollection
29
+ */
30
+ public function fromCart(GetServiceQuoteFromCart $request)
31
+ {
32
+ $requestId = ServiceQuote::generatePublicId('request');
33
+ $origin = $this->getPlaceFromId($request->input('origin'));
34
+ $destination = $this->getPlaceFromId($request->input('destination'));
35
+ $facilitator = $request->input('facilitator');
36
+ $scheduledAt = $request->input('scheduled_at');
37
+ $serviceType = $request->input('service_type');
38
+ $cart = Cart::retrieve($request->input('cart'));
39
+ $currency = $cart->currency;
40
+ $config = $request->input('config', 'storefront');
41
+ $all = $request->boolean('all');
42
+ $isRouteOptimized = $request->boolean('is_route_optimized', true);
43
+ $isNetwork = Str::startsWith(session('storefront_key'), 'network_');
44
+
45
+ if ($isNetwork) {
46
+ return $this->fromCartForNetwork($request);
47
+ }
48
+
49
+ if (!$origin) {
50
+ return response()->error('No delivery origin!');
51
+ }
52
+
53
+ if (!$destination) {
54
+ return response()->error('No delivery destination!');
55
+ }
56
+
57
+ // if no cart respond with error
58
+ if (!$cart) {
59
+ return response()->error('Cart session not found!');
60
+ }
61
+
62
+ // if facilitator is an integrated partner resolve service quotes from bridge
63
+ if ($facilitator && Utils::isIntegratedVendorId($facilitator)) {
64
+ $integratedVendor = IntegratedVendor::where('company_uuid', session('company'))->where(function ($q) use ($facilitator) {
65
+ $q->where('public_id', $facilitator);
66
+ $q->orWhere('provider', $facilitator);
67
+ })->first();
68
+
69
+ if ($integratedVendor) {
70
+ try {
71
+ /** @var \Fleetbase\Models\ServiceQuote $serviceQuote */
72
+ $serviceQuote = $integratedVendor->api()->setRequestId($requestId)->getQuoteFromPreliminaryPayload([$origin, $destination], [], $serviceType, $scheduledAt, $isRouteOptimized);
73
+ } catch (\Exception $e) {
74
+ return response()->error($e->getMessage());
75
+ }
76
+ }
77
+
78
+ // set origin and destination in service quote meta
79
+ $serviceQuote->updateMeta([
80
+ 'origin' => $origin->public_id,
81
+ 'destination' => $destination->public_id,
82
+ ]);
83
+
84
+ return new ServiceQuoteResource($serviceQuote);
85
+ }
86
+
87
+ // get distance matrix
88
+ $matrix = Utils::getDrivingDistanceAndTime($origin, $destination);
89
+
90
+ // create entities from cart items
91
+ $entities = collect($cart->items ?? [])->map(function ($cartItem) {
92
+ $product = Product::where('public_id', $cartItem->product_id)->first();
93
+
94
+ return Entity::fromStorefrontProduct($product);
95
+ });
96
+
97
+ // prepare to collect service quotes
98
+ $serviceQuotes = collect();
99
+
100
+ // get order configurations for ecommerce / task
101
+ $orderConfigs = Flow::queryOrderConfigurations(function (&$query) use ($config) {
102
+ $query->where('key', $config);
103
+ });
104
+
105
+ // get service rates for config type
106
+ $serviceRates = ServiceRate::whereIn('service_type', $orderConfigs->pluck('key'))->get();
107
+
108
+ // if no service rates send an empty quote
109
+ if ($serviceRates->isEmpty()) {
110
+ // if service rates is empty but there is integrated vendors, get quote from integrated vendors
111
+ $integratedVendor = IntegratedVendor::where('company_uuid', session('company'))->first();
112
+
113
+ if ($integratedVendor) {
114
+ try {
115
+ /** @var \Fleetbase\Models\ServiceQuote $serviceQuote */
116
+ $serviceQuote = $integratedVendor->api()->setRequestId($requestId)->getQuoteFromPreliminaryPayload([$origin, $destination], [], $serviceType, $scheduledAt, $isRouteOptimized);
117
+ } catch (\Exception $e) {
118
+ return response()->error($e->getMessage());
119
+ }
120
+
121
+ // set origin and destination in service quote meta
122
+ $serviceQuote->updateMeta([
123
+ 'origin' => $origin->public_id,
124
+ 'destination' => $destination->public_id,
125
+ ]);
126
+
127
+ return new ServiceQuoteResource($serviceQuote);
128
+ }
129
+
130
+ return response()->error('No service rates available!');
131
+ }
132
+
133
+ foreach ($serviceRates as $serviceRate) {
134
+ // get a quote from each rate and send back the best
135
+ [$subTotal, $lines] = $serviceRate->quoteFromPreliminaryData($entities, [$origin, $destination], $matrix->distance, $matrix->time, false);
136
+
137
+ $quote = ServiceQuote::create([
138
+ 'request_id' => $requestId,
139
+ 'company_uuid' => $serviceRate->company_uuid,
140
+ 'service_rate_uuid' => $serviceRate->uuid,
141
+ 'amount' => $subTotal,
142
+ 'currency' => $serviceRate->currency,
143
+ 'meta' => [
144
+ 'origin' => $origin->public_id,
145
+ 'destination' => $destination->public_id,
146
+ ]
147
+ ]);
148
+
149
+ $items = $lines->map(function ($line) use ($quote) {
150
+ return ServiceQuoteItem::create([
151
+ 'service_quote_uuid' => $quote->uuid,
152
+ 'amount' => $line['amount'],
153
+ 'currency' => $line['currency'],
154
+ 'details' => $line['details'],
155
+ 'code' => $line['code'],
156
+ ]);
157
+ });
158
+
159
+ $quote->setRelation('items', $items);
160
+ $serviceQuotes->push($quote);
161
+ }
162
+
163
+ // if user is requesting all return all service quotes
164
+ if ($all) {
165
+ return ServiceQuoteResource::collection($serviceQuotes);
166
+ }
167
+
168
+ // filter by currency
169
+ $matchingCurrency = $serviceQuotes->where('currency', $currency);
170
+
171
+ if ($matchingCurrency->count()) {
172
+ $bestQuote = $matchingCurrency->sortBy('amount')->first();
173
+
174
+ return new ServiceQuoteResource($bestQuote);
175
+ }
176
+
177
+ // get the best service quote
178
+ $bestQuote = $serviceQuotes->sortBy('amount')->first();
179
+
180
+ return new ServiceQuoteResource($bestQuote);
181
+ }
182
+ /**
183
+ * Query for Storefront Product resources.
184
+ *
185
+ * @param \Illuminate\Http\Request $request
186
+ * @return \Fleetbase\Http\Resources\DriverCollection
187
+ */
188
+ public function fromCartForNetwork(GetServiceQuoteFromCart $request)
189
+ {
190
+ $requestId = ServiceQuote::generatePublicId('request');
191
+ // $origin = $this->getPlaceFromId($request->input('origin'));
192
+ $destination = $this->getPlaceFromId($request->input('destination'));
193
+ $facilitator = $request->input('facilitator');
194
+ $scheduledAt = $request->input('scheduled_at');
195
+ $serviceType = $request->input('service_type');
196
+ $cart = Cart::retrieve($request->input('cart'));
197
+ $currency = $cart->currency;
198
+ $config = $request->input('config', 'storefront');
199
+ $all = $request->boolean('all');
200
+ $isRouteOptimized = $request->boolean('is_route_optimized', true);
201
+
202
+ // make sure destination is set
203
+ if (!$destination) {
204
+ return response()->error('No delivery destination!');
205
+ }
206
+
207
+ // if no cart respond with error
208
+ if (!$cart) {
209
+ return response()->error('Cart session not found!');
210
+ }
211
+
212
+ // collect stores
213
+ $storeLocations = collect($cart->items)->map(function ($cartItem) {
214
+ $storeLocationId = $cartItem->store_location_id;
215
+
216
+ // if no store location id set, use first locations id
217
+ if (!$storeLocationId) {
218
+ $store = Store::where('public_id', $cartItem->store_id)->first();
219
+
220
+ if ($store) {
221
+ $storeLocationId = Utils::get($store, 'locations.0.public_id');
222
+ }
223
+ }
224
+
225
+ return $storeLocationId;
226
+ })->unique()->filter()->map(function ($storeLocationId) {
227
+ return StoreLocation::where('public_id', $storeLocationId)->with(['store', 'place'])->first();
228
+ });
229
+
230
+ // fallback store locations using origin param
231
+ if ($storeLocations->isEmpty()) {
232
+ $storeLocationIds = $request->input('origin', []);
233
+
234
+ if (is_string($storeLocationIds) && Str::contains($storeLocationIds, ',')) {
235
+ $storeLocationIds = explode(',', $storeLocationIds);
236
+ }
237
+
238
+ $storeLocations = collect($storeLocationIds)->unique()->filter()->map(function ($storeLocationId) {
239
+ return StoreLocation::where('public_id', $storeLocationId)->with(['store', 'place'])->first();
240
+ });
241
+ }
242
+
243
+ // get origins
244
+ $origins = $storeLocations->map(function ($storeLocation) {
245
+ return $storeLocation->place;
246
+ });
247
+
248
+ // if facilitator is an integrated partner resolve service quotes from bridge
249
+ if ($facilitator && Utils::isIntegratedVendorId($facilitator)) {
250
+ $integratedVendor = IntegratedVendor::where('company_uuid', session('company'))->where(function ($q) use ($facilitator) {
251
+ $q->where('public_id', $facilitator);
252
+ $q->orWhere('provider', $facilitator);
253
+ })->first();
254
+
255
+ if ($integratedVendor) {
256
+ try {
257
+ /** @var \Fleetbase\Models\ServiceQuote $serviceQuote */
258
+ $serviceQuote = $integratedVendor->api()->setRequestId($requestId)->getQuoteFromPreliminaryPayload([...$origins, $destination], [], $serviceType, $scheduledAt, $isRouteOptimized);
259
+ } catch (\Exception $e) {
260
+ return response()->error($e->getMessage());
261
+ }
262
+ }
263
+
264
+ // set origin and destination in service quote meta
265
+ $serviceQuote->updateMeta([
266
+ 'origin' => $origins->pluck('public_id')->toArray(),
267
+ 'destination' => $destination->public_id,
268
+ ]);
269
+
270
+ return new ServiceQuoteResource($serviceQuote);
271
+ }
272
+
273
+ // get distance matrix
274
+ // $matrix = Utils::getDrivingDistanceAndTime($origin, $destination);
275
+ $matrix = Utils::distanceMatrix($origins, [$destination]);
276
+
277
+ // create entities from cart items
278
+ $entities = collect($cart->items ?? [])->map(function ($cartItem) {
279
+ $product = Product::where('public_id', $cartItem->product_id)->first();
280
+
281
+ return Entity::fromStorefrontProduct($product);
282
+ });
283
+
284
+ // prepare to collect service quotes
285
+ $serviceQuotes = collect();
286
+
287
+ // get order configurations for ecommerce / task
288
+ $orderConfigs = Flow::queryOrderConfigurations(function (&$query) use ($config) {
289
+ $query->where('key', $config);
290
+ });
291
+
292
+ // get service rates for config type
293
+ $serviceRates = ServiceRate::whereIn('service_type', $orderConfigs->pluck('key'))->get();
294
+
295
+ // if no service rates send an empty quote
296
+ if ($serviceRates->isEmpty()) {
297
+ // if service rates is empty but there is integrated vendors, get quote from integrated vendors
298
+ $integratedVendor = IntegratedVendor::where('company_uuid', session('company'))->first();
299
+
300
+ if ($integratedVendor) {
301
+ try {
302
+ /** @var \Fleetbase\FleetOps\Models\ServiceQuote $serviceQuote */
303
+ $serviceQuote = $integratedVendor->api()->setRequestId($requestId)->getQuoteFromPreliminaryPayload([...$origins, $destination], [], $serviceType, $scheduledAt, $isRouteOptimized);
304
+ } catch (\Exception $e) {
305
+ return response()->error($e->getMessage());
306
+ }
307
+
308
+ // set origin and destination in service quote meta
309
+ $serviceQuote->updateMeta([
310
+ 'origin' => $origins->pluck('public_id')->toArray(),
311
+ 'destination' => $destination->public_id,
312
+ ]);
313
+
314
+ return new ServiceQuoteResource($serviceQuote);
315
+ }
316
+
317
+ return response()->error('No service rates available!');
318
+ }
319
+
320
+ foreach ($serviceRates as $serviceRate) {
321
+ // get a quote from each rate and send back the best
322
+ [$subTotal, $lines] = $serviceRate->quoteFromPreliminaryData($entities, [...$origins, $destination], $matrix->distance, $matrix->time, false);
323
+
324
+ $quote = ServiceQuote::create([
325
+ 'request_id' => $requestId,
326
+ 'company_uuid' => $serviceRate->company_uuid,
327
+ 'service_rate_uuid' => $serviceRate->uuid,
328
+ 'amount' => $subTotal,
329
+ 'currency' => $serviceRate->currency,
330
+ 'meta' => [
331
+ 'origin' => $origins->pluck('public_id')->toArray(),
332
+ 'destination' => $destination->public_id,
333
+ ]
334
+ ]);
335
+
336
+ $items = $lines->map(function ($line) use ($quote) {
337
+ return ServiceQuoteItem::create([
338
+ 'service_quote_uuid' => $quote->uuid,
339
+ 'amount' => $line['amount'],
340
+ 'currency' => $line['currency'],
341
+ 'details' => $line['details'],
342
+ 'code' => $line['code'],
343
+ ]);
344
+ });
345
+
346
+ $quote->setRelation('items', $items);
347
+ $serviceQuotes->push($quote);
348
+ }
349
+
350
+ // if user is requesting all return all service quotes
351
+ if ($all) {
352
+ return ServiceQuoteResource::collection($serviceQuotes);
353
+ }
354
+
355
+ // filter by currency
356
+ $matchingCurrency = $serviceQuotes->where('currency', $currency);
357
+
358
+ if ($matchingCurrency->count()) {
359
+ $bestQuote = $matchingCurrency->sortBy('amount')->first();
360
+
361
+ return new ServiceQuoteResource($bestQuote);
362
+ }
363
+
364
+ // get the best service quote
365
+ $bestQuote = $serviceQuotes->sortBy('amount')->first();
366
+
367
+ return new ServiceQuoteResource($bestQuote);
368
+ }
369
+
370
+ /**
371
+ * Returns a place from either a place id or store location id.
372
+ *
373
+ * @param string $id
374
+ * @return Place
375
+ */
376
+ public function getPlaceFromId($id)
377
+ {
378
+ if (Str::startsWith($id, 'store_location')) {
379
+ $storeLocation = StoreLocation::select(['place_uuid'])->where(['public_id' => $id, 'store_uuid' => session('storefront_store')])->with(['place'])->first();
380
+
381
+ if (!$storeLocation) {
382
+ return null;
383
+ }
384
+
385
+ return $storeLocation->place;
386
+ }
387
+
388
+ if (Str::startsWith($id, 'place')) {
389
+ return Place::where(['public_id' => $id, 'company_uuid' => session('company')])->first();
390
+ }
391
+
392
+ // handle coordinates tooo!
393
+ if (!Str::startsWith($id, ['place_', 'store_location']) && Utils::isCoordinates($id)) {
394
+ $point = Utils::getPointFromCoordinates($id);
395
+ $place = Place::createFromCoordinates($point, ['company_uuid' => session('company')], true);
396
+
397
+ return $place;
398
+ }
399
+
400
+ return Place::where(['public_id' => $id, 'company_uuid' => session('company')])->first();
401
+ }
402
+ }
@@ -0,0 +1,176 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\Storefront\Http\Controllers\v1;
4
+
5
+ use Fleetbase\Http\Controllers\Controller;
6
+ use Fleetbase\Storefront\Http\Resources\Gateway as GatewayResource;
7
+ use Fleetbase\Storefront\Http\Resources\Network;
8
+ use Fleetbase\Storefront\Http\Resources\Product as ProductResource;
9
+ use Fleetbase\Storefront\Http\Resources\Store as StorefrontStore;
10
+ use Fleetbase\Storefront\Http\Resources\StoreLocation as StoreLocationResource;
11
+ use Fleetbase\Storefront\Models\Gateway;
12
+ use Fleetbase\Storefront\Models\Product;
13
+ use Fleetbase\Storefront\Models\Store;
14
+ use Fleetbase\Storefront\Models\StoreLocation;
15
+ use Fleetbase\Storefront\Support\Storefront;
16
+ use Illuminate\Http\Request;
17
+ use Illuminate\Support\Str;
18
+
19
+ class StoreController extends Controller
20
+ {
21
+ /**
22
+ * Returns general information and settings about the storefront or network given the key.
23
+ *
24
+ * @param \Illuminate\Http\Request $request
25
+ * @return \Illuminate\Http\Response
26
+ */
27
+ public function about()
28
+ {
29
+ $about = Storefront::about('*');
30
+
31
+ if (!$about) {
32
+ return response()->error('Unable to find store!');
33
+ }
34
+
35
+ if ($about->is_store) {
36
+ return new StorefrontStore($about);
37
+ }
38
+
39
+ return new Network($about);
40
+ }
41
+
42
+ /**
43
+ * Returns all locations and their hours for the current store.
44
+ *
45
+ * @param \Illuminate\Http\Request $request
46
+ * @return \Illuminate\Http\Response
47
+ */
48
+ public function locations(Request $request)
49
+ {
50
+ if (session('storefront_network') && $request->missing('store')) {
51
+ return response()->error('Networks cannot have locations!');
52
+ }
53
+
54
+ if ($request->filled('store')) {
55
+ $locations = StoreLocation::whereHas('store', function ($q) use ($request) {
56
+ $q->where('public_id', $request->input('store'));
57
+ })->with(['place', 'hours'])->get();
58
+ } else {
59
+ $locations = StoreLocation::where('store_uuid', session('storefront_store'))->with(['place', 'hours'])->get();
60
+ }
61
+
62
+ return StoreLocationResource::collection($locations);
63
+ }
64
+
65
+ /**
66
+ * Returns a specific store location given the id.
67
+ *
68
+ * @param string $id
69
+ * @param \Illuminate\Http\Request $request
70
+ * @return \Illuminate\Http\Response
71
+ */
72
+ public function location(string $id, Request $request)
73
+ {
74
+ if (session('storefront_network') && $request->missing('store')) {
75
+ return response()->error('Networks cannot have locations!');
76
+ }
77
+
78
+ $storeId = $request->input('store', session('storefront_store'));
79
+ $store = Store::where('public_id', $storeId)->orWhere('uuid', $storeId)->first();
80
+
81
+ $location = StoreLocation::where([
82
+ 'public_id' => $id,
83
+ 'store_uuid' => $store->uuid
84
+ ])
85
+ ->with(['place', 'hours'])
86
+ ->first();
87
+
88
+ return new StoreLocationResource($location);
89
+ }
90
+
91
+ /**
92
+ * Returns all payment gateways for the current store.
93
+ *
94
+ * @param \Illuminate\Http\Request $request
95
+ * @return \Illuminate\Http\Response
96
+ */
97
+ public function gateways(Request $request)
98
+ {
99
+ $id = session('storefront_store') ?? session('storefront_network');
100
+
101
+ $sandbox = $request->input('sandbox', false);
102
+ $query = Gateway::select(['public_id', 'name', 'code', 'type', 'sandbox', 'return_url', 'callback_url'])->where('owner_uuid', $id);
103
+
104
+ if ($sandbox) {
105
+ $query->where('sandbox', 1);
106
+ }
107
+
108
+ // fetch all gateways available
109
+ $gateways = $query->get();
110
+
111
+ // create cod/cash gateway if enabled
112
+ // @var \Fleetbase\Models\Storefront\Store|\Fleetbase\Models\Storefront\Network $about
113
+ $about = Storefront::about();
114
+
115
+ // if cod is enabled add cash as a gateway
116
+ if ($about->hasOption('cod_enabled')) {
117
+ $gateways->push(Gateway::cash($sandbox));
118
+ }
119
+
120
+ return GatewayResource::collection($gateways);
121
+ }
122
+
123
+ /**
124
+ * Returns a specific payment gateway given the id.
125
+ *
126
+ * @param string $id
127
+ * @param \Illuminate\Http\Request $request
128
+ * @return \Illuminate\Http\Response
129
+ */
130
+ public function gateway(string $id, Request $request)
131
+ {
132
+ $ownerId = session('storefront_store') ?? session('storefront_network');
133
+
134
+ $sandbox = $request->input('sandbox', false);
135
+ $query = Gateway::select(['public_id', 'name', 'code', 'type', 'sandbox', 'return_url', 'callback_url'])->where(['public_id' => $id, 'owner_uuid' => $ownerId]);
136
+
137
+ if ($sandbox) {
138
+ $query->where('sandbox', 1);
139
+ }
140
+
141
+ // fetch all gateways available
142
+ $gateway = $query->first();
143
+
144
+ return new GatewayResource($gateway);
145
+ }
146
+
147
+ /**
148
+ * Search current store or network.
149
+ *
150
+ * @param \Illuminate\Http\Request $request
151
+ * @return \Illuminate\Http\Response
152
+ */
153
+ public function search(Request $request)
154
+ {
155
+ $searchQuery = $request->input('query', '');
156
+ $limit = $request->input('limit', 14);
157
+ $store = $request->input('store');
158
+ $key = session('storefront_key');
159
+
160
+ if (Str::startsWith($key, 'store')) {
161
+ $results = Product::where('store_uuid', session('storefront_store'))
162
+ ->search($searchQuery)
163
+ ->limit($limit)
164
+ ->whereNull('deleted_at')
165
+ ->whereIsAvailable(1)
166
+ ->whereStatus('published')
167
+ ->get();
168
+
169
+ return ProductResource::collection($results);
170
+ }
171
+
172
+ $results = Product::findFromNetwork($searchQuery, $store, $limit);
173
+
174
+ return ProductResource::collection($results);
175
+ }
176
+ }
@@ -0,0 +1,19 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\Storefront\Http\Filter;
4
+
5
+ use Fleetbase\Http\Filter\Filter;
6
+
7
+ class AddonCategoryFilter extends Filter
8
+ {
9
+ public function queryForInternal()
10
+ {
11
+ // Query only this company sessions resources
12
+ $this->builder->where(
13
+ [
14
+ 'company_uuid' => $this->session->get('company'),
15
+ 'for' => 'storefront_product_addon'
16
+ ]
17
+ );
18
+ }
19
+ }
@@ -0,0 +1,18 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\Storefront\Http\Filter;
4
+
5
+ use Fleetbase\FleetOps\Http\Filter\ContactFilter;
6
+
7
+ class CustomerFilter extends ContactFilter
8
+ {
9
+ public function storefront($storefront)
10
+ {
11
+ $this->builder->whereHas(
12
+ 'customerOrders',
13
+ function ($query) use ($storefront) {
14
+ $query->where('meta->storefront_id', $storefront);
15
+ }
16
+ );
17
+ }
18
+ }
@@ -0,0 +1,13 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\Storefront\Http\Filter;
4
+
5
+ use Fleetbase\Http\Filter\Filter;
6
+
7
+ class GatewayFilter extends Filter
8
+ {
9
+ public function queryForInternal()
10
+ {
11
+ $this->builder->where('company_uuid', $this->session->get('company'));
12
+ }
13
+ }
@@ -0,0 +1,18 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\Storefront\Http\Filter;
4
+
5
+ use Fleetbase\Http\Filter\Filter;
6
+
7
+ class NetworkFilter extends Filter
8
+ {
9
+ public function queryForInternal()
10
+ {
11
+ $this->builder->where('company_uuid', $this->session->get('company'));
12
+ }
13
+
14
+ public function query(?string $searchQuery)
15
+ {
16
+ $this->builder->search($searchQuery);
17
+ }
18
+ }
@@ -0,0 +1,13 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\Storefront\Http\Filter;
4
+
5
+ use Fleetbase\Http\Filter\Filter;
6
+
7
+ class NotificationChannelFilter extends Filter
8
+ {
9
+ public function queryForInternal()
10
+ {
11
+ $this->builder->where('company_uuid', $this->session->get('company'));
12
+ }
13
+ }