@fleetbase/storefront-engine 0.1.7 → 0.1.9

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 (163) hide show
  1. package/.php-cs-fixer.php +29 -0
  2. package/LICENSE.md +16 -4
  3. package/README.md +106 -13
  4. package/composer.json +88 -0
  5. package/extension.json +10 -0
  6. package/package.json +6 -6
  7. package/phpstan.neon.dist +8 -0
  8. package/phpunit.xml.dist +16 -0
  9. package/server/.gitattributes +14 -0
  10. package/server/README.md +40 -0
  11. package/server/config/api.php +101 -0
  12. package/server/config/database.connections.php +57 -0
  13. package/server/config/storefront.php +19 -0
  14. package/server/config/twilio-notification-channel.php +36 -0
  15. package/server/migrations/2023_05_03_025307_create_carts_table.php +44 -0
  16. package/server/migrations/2023_05_03_025307_create_checkouts_table.php +51 -0
  17. package/server/migrations/2023_05_03_025307_create_gateways_table.php +48 -0
  18. package/server/migrations/2023_05_03_025307_create_network_stores_table.php +36 -0
  19. package/server/migrations/2023_05_03_025307_create_networks_table.php +56 -0
  20. package/server/migrations/2023_05_03_025307_create_notification_channels_table.php +43 -0
  21. package/server/migrations/2023_05_03_025307_create_payment_methods_table.php +44 -0
  22. package/server/migrations/2023_05_03_025307_create_product_addon_categories_table.php +38 -0
  23. package/server/migrations/2023_05_03_025307_create_product_addons_table.php +43 -0
  24. package/server/migrations/2023_05_03_025307_create_product_hours_table.php +37 -0
  25. package/server/migrations/2023_05_03_025307_create_product_store_locations_table.php +34 -0
  26. package/server/migrations/2023_05_03_025307_create_product_variant_options_table.php +40 -0
  27. package/server/migrations/2023_05_03_025307_create_product_variants_table.php +44 -0
  28. package/server/migrations/2023_05_03_025307_create_products_table.php +59 -0
  29. package/server/migrations/2023_05_03_025307_create_reviews_table.php +41 -0
  30. package/server/migrations/2023_05_03_025307_create_store_hours_table.php +37 -0
  31. package/server/migrations/2023_05_03_025307_create_store_locations_table.php +38 -0
  32. package/server/migrations/2023_05_03_025307_create_stores_table.php +57 -0
  33. package/server/migrations/2023_05_03_025307_create_votes_table.php +39 -0
  34. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_carts_table.php +40 -0
  35. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_checkouts_table.php +48 -0
  36. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_gateways_table.php +40 -0
  37. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_network_stores_table.php +40 -0
  38. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_networks_table.php +42 -0
  39. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_notification_channels_table.php +40 -0
  40. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_payment_methods_table.php +40 -0
  41. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_addon_categories_table.php +38 -0
  42. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_addons_table.php +38 -0
  43. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_hours_table.php +32 -0
  44. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_store_locations_table.php +34 -0
  45. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_variant_options_table.php +32 -0
  46. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_variants_table.php +32 -0
  47. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_products_table.php +44 -0
  48. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_reviews_table.php +38 -0
  49. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_store_hours_table.php +32 -0
  50. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_store_locations_table.php +40 -0
  51. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_stores_table.php +42 -0
  52. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_votes_table.php +38 -0
  53. package/server/src/Auth/Schemas/Storefront.php +95 -0
  54. package/server/src/Console/Commands/NotifyStorefrontOrderNearby.php +86 -0
  55. package/server/src/Expansions/EntityExpansion.php +44 -0
  56. package/server/src/Http/Controllers/ActionController.php +119 -0
  57. package/server/src/Http/Controllers/AddonCategoryController.php +13 -0
  58. package/server/src/Http/Controllers/CustomerController.php +13 -0
  59. package/server/src/Http/Controllers/GatewayController.php +13 -0
  60. package/server/src/Http/Controllers/MetricsController.php +71 -0
  61. package/server/src/Http/Controllers/NetworkController.php +170 -0
  62. package/server/src/Http/Controllers/NotificationChannelController.php +13 -0
  63. package/server/src/Http/Controllers/OrderController.php +154 -0
  64. package/server/src/Http/Controllers/ProductAddonCategoryController.php +14 -0
  65. package/server/src/Http/Controllers/ProductAddonController.php +14 -0
  66. package/server/src/Http/Controllers/ProductController.php +123 -0
  67. package/server/src/Http/Controllers/ProductHourController.php +13 -0
  68. package/server/src/Http/Controllers/ProductVariantController.php +13 -0
  69. package/server/src/Http/Controllers/ProductVariantOptionController.php +13 -0
  70. package/server/src/Http/Controllers/ReviewController.php +13 -0
  71. package/server/src/Http/Controllers/StoreController.php +26 -0
  72. package/server/src/Http/Controllers/StoreHourController.php +13 -0
  73. package/server/src/Http/Controllers/StoreLocationController.php +13 -0
  74. package/server/src/Http/Controllers/StorefrontController.php +15 -0
  75. package/server/src/Http/Controllers/VoteController.php +13 -0
  76. package/server/src/Http/Controllers/v1/CartController.php +161 -0
  77. package/server/src/Http/Controllers/v1/CategoryController.php +138 -0
  78. package/server/src/Http/Controllers/v1/CheckoutController.php +957 -0
  79. package/server/src/Http/Controllers/v1/CustomerController.php +482 -0
  80. package/server/src/Http/Controllers/v1/GatewayControllerController.php +11 -0
  81. package/server/src/Http/Controllers/v1/NetworkController.php +281 -0
  82. package/server/src/Http/Controllers/v1/PaymentMethodController.php +11 -0
  83. package/server/src/Http/Controllers/v1/ProductController.php +94 -0
  84. package/server/src/Http/Controllers/v1/ReviewController.php +270 -0
  85. package/server/src/Http/Controllers/v1/ServiceQuoteController.php +402 -0
  86. package/server/src/Http/Controllers/v1/StoreController.php +176 -0
  87. package/server/src/Http/Filter/AddonCategoryFilter.php +19 -0
  88. package/server/src/Http/Filter/CustomerFilter.php +18 -0
  89. package/server/src/Http/Filter/GatewayFilter.php +13 -0
  90. package/server/src/Http/Filter/NetworkFilter.php +18 -0
  91. package/server/src/Http/Filter/NotificationChannelFilter.php +13 -0
  92. package/server/src/Http/Filter/OrderFilter.php +46 -0
  93. package/server/src/Http/Filter/ProductFilter.php +28 -0
  94. package/server/src/Http/Filter/StoreFilter.php +42 -0
  95. package/server/src/Http/Filter/StoreLocationFilter.php +23 -0
  96. package/server/src/Http/Middleware/SetStorefrontSession.php +130 -0
  97. package/server/src/Http/Requests/AddStoreToNetworkCategory.php +45 -0
  98. package/server/src/Http/Requests/CaptureOrderRequest.php +30 -0
  99. package/server/src/Http/Requests/CreateCustomerRequest.php +44 -0
  100. package/server/src/Http/Requests/CreateReviewRequest.php +34 -0
  101. package/server/src/Http/Requests/GetServiceQuoteFromCart.php +40 -0
  102. package/server/src/Http/Requests/InitializeCheckoutRequest.php +38 -0
  103. package/server/src/Http/Requests/NetworkActionRequest.php +43 -0
  104. package/server/src/Http/Requests/VerifyCreateCustomerRequest.php +31 -0
  105. package/server/src/Http/Resources/Cart.php +31 -0
  106. package/server/src/Http/Resources/Category.php +48 -0
  107. package/server/src/Http/Resources/Customer.php +36 -0
  108. package/server/src/Http/Resources/Gateway.php +32 -0
  109. package/server/src/Http/Resources/Media.php +29 -0
  110. package/server/src/Http/Resources/Network.php +48 -0
  111. package/server/src/Http/Resources/Product.php +209 -0
  112. package/server/src/Http/Resources/Review.php +45 -0
  113. package/server/src/Http/Resources/ReviewCustomer.php +60 -0
  114. package/server/src/Http/Resources/Store.php +76 -0
  115. package/server/src/Http/Resources/StoreHour.php +29 -0
  116. package/server/src/Http/Resources/StoreLocation.php +33 -0
  117. package/server/src/Imports/ProductsImport.php +20 -0
  118. package/server/src/Jobs/DownloadProductImageUrl.php +60 -0
  119. package/server/src/Listeners/HandleOrderCompleted.php +31 -0
  120. package/server/src/Listeners/HandleOrderDispatched.php +34 -0
  121. package/server/src/Listeners/HandleOrderDriverAssigned.php +37 -0
  122. package/server/src/Listeners/HandleOrderStarted.php +27 -0
  123. package/server/src/Mail/StorefrontNetworkInvite.php +48 -0
  124. package/server/src/Models/AddonCategory.php +30 -0
  125. package/server/src/Models/Cart.php +691 -0
  126. package/server/src/Models/Checkout.php +166 -0
  127. package/server/src/Models/Customer.php +88 -0
  128. package/server/src/Models/Gateway.php +165 -0
  129. package/server/src/Models/Network.php +300 -0
  130. package/server/src/Models/NetworkStore.php +86 -0
  131. package/server/src/Models/NotificationChannel.php +147 -0
  132. package/server/src/Models/PaymentMethod.php +99 -0
  133. package/server/src/Models/Product.php +315 -0
  134. package/server/src/Models/ProductAddon.php +128 -0
  135. package/server/src/Models/ProductAddonCategory.php +90 -0
  136. package/server/src/Models/ProductHour.php +59 -0
  137. package/server/src/Models/ProductStoreLocation.php +77 -0
  138. package/server/src/Models/ProductVariant.php +125 -0
  139. package/server/src/Models/ProductVariantOption.php +86 -0
  140. package/server/src/Models/Review.php +127 -0
  141. package/server/src/Models/Store.php +478 -0
  142. package/server/src/Models/StoreHour.php +59 -0
  143. package/server/src/Models/StoreLocation.php +126 -0
  144. package/server/src/Models/StorefrontModel.php +22 -0
  145. package/server/src/Models/Vote.php +84 -0
  146. package/server/src/Notifications/StorefrontOrderCanceled.php +196 -0
  147. package/server/src/Notifications/StorefrontOrderCompleted.php +201 -0
  148. package/server/src/Notifications/StorefrontOrderCreated.php +157 -0
  149. package/server/src/Notifications/StorefrontOrderDriverAssigned.php +200 -0
  150. package/server/src/Notifications/StorefrontOrderEnroute.php +199 -0
  151. package/server/src/Notifications/StorefrontOrderNearby.php +201 -0
  152. package/server/src/Notifications/StorefrontOrderPreparing.php +202 -0
  153. package/server/src/Notifications/StorefrontOrderReadyForPickup.php +202 -0
  154. package/server/src/Observers/NetworkObserver.php +40 -0
  155. package/server/src/Observers/ProductObserver.php +118 -0
  156. package/server/src/Providers/EventServiceProvider.php +23 -0
  157. package/server/src/Providers/StorefrontServiceProvider.php +103 -0
  158. package/server/src/Support/Metrics.php +193 -0
  159. package/server/src/Support/OrderConfig.php +13 -0
  160. package/server/src/Support/QPay.php +208 -0
  161. package/server/src/Support/Storefront.php +201 -0
  162. package/server/src/routes.php +180 -0
  163. package/server/tests/Feature.php +5 -0
@@ -0,0 +1,193 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\Storefront\Support;
4
+
5
+ use Fleetbase\Models\Company;
6
+ use Fleetbase\Storefront\Models\Network;
7
+ use Fleetbase\Storefront\Models\Store;
8
+ use Fleetbase\Storefront\Models\Product;
9
+ use Fleetbase\FleetOps\Models\Order;
10
+ use Illuminate\Support\Carbon;
11
+ use Illuminate\Support\Str;
12
+
13
+ /**
14
+ * Metrics service to pull analyitcs and metrics from Storefront.
15
+ *
16
+ * Ex:
17
+ * $metrics = Metrics::new($company)->withTotalStores()->withOrdersCanceled()->get();
18
+ */
19
+ class Metrics
20
+ {
21
+ protected \DateTime $start;
22
+ protected \DateTime $end;
23
+ protected Company $company;
24
+ protected array $metrics = [];
25
+
26
+ public static function new(Company $company, ?\DateTime $start = null, ?\DateTime $end = null): Metrics
27
+ {
28
+ $start = $start === null ? Carbon::create(1900)->toDateTime() : $start;
29
+ $end = $end === null ? Carbon::tomorrow()->toDateTime() : $end;
30
+
31
+ return (new static())->setCompany($company)->between($start, $end);
32
+ }
33
+
34
+ public static function forCompany(Company $company, ?\DateTime $start = null, ?\DateTime $end = null): Metrics
35
+ {
36
+ return static::new($company, $start, $end);
37
+ }
38
+
39
+ public function start(\DateTime $start): Metrics
40
+ {
41
+ $this->start = $start;
42
+
43
+ return $this;
44
+ }
45
+
46
+ public function end(\DateTime $end): Metrics
47
+ {
48
+ $this->end = $end;
49
+
50
+ return $this;
51
+ }
52
+
53
+ public function between(\DateTime $start, \DateTime $end): Metrics
54
+ {
55
+ return $this->start($start)->end($end);
56
+ }
57
+
58
+ private function setCompany(Company $company): Metrics
59
+ {
60
+ $this->company = $company;
61
+
62
+ return $this;
63
+ }
64
+
65
+ private function set($key, $value = null): Metrics
66
+ {
67
+ if (is_array($key)) {
68
+ foreach ($key as $k => $v) {
69
+ $this->set($k, $v);
70
+ }
71
+
72
+ return $this;
73
+ }
74
+
75
+ $this->metrics = data_set($this->metrics, $key, $value);
76
+
77
+ return $this;
78
+ }
79
+
80
+ public function get()
81
+ {
82
+ return $this->metrics;
83
+ }
84
+
85
+ public function with(?array $metrics = [])
86
+ {
87
+ if (empty($metrics)) {
88
+ $metrics = array_slice(get_class_methods($this), 9);
89
+ }
90
+
91
+ $metrics = array_map(
92
+ function ($metric) {
93
+ return Str::camel($metric);
94
+ },
95
+ $metrics
96
+ );
97
+
98
+ foreach ($metrics as $metric) {
99
+ if (method_exists($this, $metric)) {
100
+ $this->{$metric}();
101
+ }
102
+ }
103
+
104
+ return $this;
105
+ }
106
+
107
+ public function totalProducts(?callable $callback = null): Metrics
108
+ {
109
+ $query = Product::where('company_uuid', $this->company->uuid);
110
+
111
+ if (is_callable($callback)) {
112
+ $callback($query);
113
+ }
114
+
115
+ $data = $query->count();
116
+
117
+ return $this->set('total_products', $data);
118
+ }
119
+
120
+ public function totalStores(?callable $callback = null): Metrics
121
+ {
122
+ $query = Store::where('company_uuid', $this->company->uuid);
123
+
124
+ if (is_callable($callback)) {
125
+ $callback($query);
126
+ }
127
+
128
+ $data = $query->count();
129
+
130
+ return $this->set('total_stores', $data);
131
+ }
132
+
133
+ public function totalNetworks(?callable $callback = null): Metrics
134
+ {
135
+ $query = Network::where('company_uuid', $this->company->uuid);
136
+
137
+ if (is_callable($callback)) {
138
+ $callback($query);
139
+ }
140
+
141
+ $data = $query->count();
142
+
143
+ return $this->set('total_networks', $data);
144
+ }
145
+
146
+ public function ordersInProgress(?callable $callback = null): Metrics
147
+ {
148
+ $query = Order::where('company_uuid', $this->company->uuid)
149
+ ->whereBetween('created_at', [$this->start, $this->end])
150
+ ->where('type', 'storefront')
151
+ ->whereNotIn('status', ['completed', 'created', 'pending', 'canceled']);
152
+
153
+ if (is_callable($callback)) {
154
+ $callback($query);
155
+ }
156
+
157
+ $data = $query->count();
158
+
159
+ return $this->set('orders_in_progress', $data);
160
+ }
161
+
162
+ public function ordersCompleted(?callable $callback = null): Metrics
163
+ {
164
+ $query = Order::where('company_uuid', $this->company->uuid)
165
+ ->whereBetween('created_at', [$this->start, $this->end])
166
+ ->where('type', 'storefront')
167
+ ->where('status', 'completed');
168
+
169
+ if (is_callable($callback)) {
170
+ $callback($query);
171
+ }
172
+
173
+ $data = $query->count();
174
+
175
+ return $this->set('orders_completed', $data);
176
+ }
177
+
178
+ public function ordersCanceled(?callable $callback = null): Metrics
179
+ {
180
+ $query = Order::where('company_uuid', $this->company->uuid)
181
+ ->whereBetween('created_at', [$this->start, $this->end])
182
+ ->where('type', 'storefront')
183
+ ->where('status', 'canceled');
184
+
185
+ if (is_callable($callback)) {
186
+ $callback($query);
187
+ }
188
+
189
+ $data = $query->count();
190
+
191
+ return $this->set('orders_canceled', $data);
192
+ }
193
+ }
@@ -0,0 +1,13 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\Storefront\Support;
4
+
5
+ class OrderConfig {
6
+ /**
7
+ * Provides default order configs for Storefront.
8
+ */
9
+ public function get(): ?array
10
+ {
11
+ return config('storefront.api.types.order', []);
12
+ }
13
+ }
@@ -0,0 +1,208 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\Storefront\Support;
4
+
5
+ use GuzzleHttp\Client;
6
+
7
+ class QPay
8
+ {
9
+ private string $host = 'https://merchant.qpay.mn/';
10
+ private string $namespace = 'v2';
11
+ private ?string $callbackUrl;
12
+ private array $requestOptions = [];
13
+ private Client $client;
14
+
15
+ public function __construct(?string $username = null, ?string $password = null, ?string $callbackUrl = null)
16
+ {
17
+ $this->callbackUrl = $callbackUrl;
18
+ $this->requestOptions = [
19
+ 'base_uri' => $this->buildRequestUrl(),
20
+ 'auth' => [$username, $password],
21
+ 'headers' => [
22
+ 'Content-Type' => 'application/json',
23
+ 'Accept' => 'application/json'
24
+ ]
25
+ ];
26
+ $this->client = new Client($this->requestOptions);
27
+ }
28
+
29
+ public function updateRequestOption($key, $value)
30
+ {
31
+ $this->requestOptions[$key] = $value;
32
+ $this->client = new Client($this->requestOptions);
33
+ }
34
+
35
+ public function getClient()
36
+ {
37
+ return $this->client;
38
+ }
39
+
40
+ public function setNamespace(string $namespace): ?QPay
41
+ {
42
+ $this->namespace = $namespace;
43
+ $this->updateRequestOption('base_uri', $this->buildRequestUrl());
44
+
45
+ return $this;
46
+ }
47
+
48
+ private function buildRequestUrl(string $path = ''): string
49
+ {
50
+ $url = trim($this->host . $this->namespace . '/' . $path);
51
+ return $url;
52
+ }
53
+
54
+ public function useSandbox()
55
+ {
56
+ $this->host = 'https://merchant-sandbox.qpay.mn/';
57
+ $this->updateRequestOption('base_uri', $this->buildRequestUrl());
58
+
59
+ return $this;
60
+ }
61
+
62
+ public static function instance(?string $username = null, ?string $password = null, ?string $callbackUrl = null): QPay
63
+ {
64
+ return new static($username, $password, $callbackUrl);
65
+ }
66
+
67
+ private function hasCallbackUrl()
68
+ {
69
+ return isset($this->callbackUrl);
70
+ }
71
+
72
+ private function request(string $method, string $path, array $options = [])
73
+ {
74
+ $options['http_errors'] = false;
75
+
76
+ $response = $this->client->request($method, $path, $options);
77
+ $body = $response->getBody();
78
+ $contents = $body->getContents();
79
+ $json = json_decode($contents);
80
+
81
+ return $json;
82
+ }
83
+
84
+ public function post(string $path, array $params = [], array $options = [])
85
+ {
86
+ $options = ['json' => $params];
87
+
88
+ return $this->request('POST', $path, $options);
89
+ }
90
+
91
+ public function delete(string $path, array $params = [], array $options = [])
92
+ {
93
+ $options = ['json' => $params];
94
+
95
+ return $this->request('DELETE', $path, $options);
96
+ }
97
+
98
+ public function get(string $path, array $options = [])
99
+ {
100
+ return $this->request('GET', $path, $options);
101
+ }
102
+
103
+ public function getAuthToken()
104
+ {
105
+ return $this->post('auth/token');
106
+ }
107
+
108
+ public function refreshAuthToken()
109
+ {
110
+ return $this->post('auth/refresh');
111
+ }
112
+
113
+ private function useBearerToken(string $token): QPay
114
+ {
115
+ unset($this->requestOptions['auth']);
116
+ $headers = array_merge($this->requestOptions['headers'] ?? [], ['Authorization' => "Bearer $token"]);
117
+ $this->updateRequestOption('headers', $headers);
118
+
119
+ return $this;
120
+ }
121
+
122
+ public function setAuthToken(?string $accessToken = null): QPay
123
+ {
124
+ if ($accessToken) {
125
+ $this->useBearerToken($accessToken);
126
+ } else {
127
+ $response = $this->getAuthToken();
128
+ $token = $response->access_token;
129
+
130
+ if (isset($token)) {
131
+ $this->useBearerToken($token);
132
+ }
133
+ }
134
+
135
+ return $this;
136
+ }
137
+
138
+ public function createSimpleInvoice(int $amount, ?string $invoiceCode = '', ?string $invoiceDescription = '', ?string $invoiceReceiverCode = '', ?string $senderInvoiceNo = '', ?string $callbackUrl = null)
139
+ {
140
+ if (!$callbackUrl && $this->hasCallbackUrl()) {
141
+ $callbackUrl = $this->callbackUrl;
142
+ }
143
+
144
+ $params = array_filter([
145
+ 'invoice_code' => $invoiceCode,
146
+ 'amount' => $amount,
147
+ 'callback_url' => $callbackUrl,
148
+ 'invoice_description' => $invoiceDescription,
149
+ 'invoice_receiver_code' => $invoiceReceiverCode,
150
+ 'sender_invoice_no' => $senderInvoiceNo,
151
+ ]);
152
+
153
+ return $this->createQPayInvoice($params);
154
+ }
155
+
156
+ public function createQPayInvoice(array $params = [], $options = [])
157
+ {
158
+ if (!isset($params['callback_url']) && $this->hasCallbackUrl()) {
159
+ $params['callback_url'] = $this->callbackUrl;
160
+ }
161
+
162
+ return $this->post('invoice', $params, $options);
163
+ }
164
+
165
+ public function paymentCheck(string $invoiceId, $options = [])
166
+ {
167
+ $params = [
168
+ 'object_type' => 'INVOICE',
169
+ 'object_id' => $invoiceId
170
+ ];
171
+
172
+ return $this->post('payment/check', $params, $options);
173
+ }
174
+
175
+ public function paymentCancel(string $invoiceId, $options = [])
176
+ {
177
+ $params = [
178
+ 'callback_url' => '"https://qpay.mn/payment/result?payment_id=' . $invoiceId,
179
+ ];
180
+
181
+ return $this->delete('payment/cancel', $params, $options);
182
+ }
183
+
184
+ public function paymentRefund(string $invoiceId, $options = [])
185
+ {
186
+ $params = [
187
+ 'callback_url' => '"https://qpay.mn/payment/result?payment_id=' . $invoiceId,
188
+ ];
189
+
190
+ return $this->delete('payment/refund', $params, $options);
191
+ }
192
+
193
+ public static function createInvoice(string $username, string $password, array $invoiceParams = [])
194
+ {
195
+ return static::instance($username, $password)->setAuthToken()->createQPayInvoice($invoiceParams);
196
+ }
197
+
198
+ public static function generateCode(string $id)
199
+ {
200
+ return date('Ymd') . $id;
201
+ }
202
+
203
+ public static function cleanCode(string $code)
204
+ {
205
+ $code = str_replace(' ', '-', $code);
206
+ return preg_replace('/[^A-Za-z0-9\-]/', '', $code);
207
+ }
208
+ }
@@ -0,0 +1,201 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\Storefront\Support;
4
+
5
+ use Fleetbase\Storefront\Models\Gateway;
6
+ use Fleetbase\Storefront\Models\Network;
7
+ use Fleetbase\Storefront\Models\Product;
8
+ use Fleetbase\Storefront\Models\Store;
9
+ use Fleetbase\FleetOps\Models\Contact;
10
+ use Fleetbase\FleetOps\Models\Order;
11
+ use Fleetbase\Models\User;
12
+ use Fleetbase\Storefront\Notifications\StorefrontOrderCreated;
13
+ use Illuminate\Support\Facades\Notification;
14
+ use Illuminate\Support\Facades\Redis;
15
+ use Illuminate\Support\Str;
16
+ use Laravel\Sanctum\PersonalAccessToken;
17
+
18
+ class Storefront
19
+ {
20
+ /**
21
+ * Returns current store or network based on session `storefront_key`
22
+ * with bare minimum columns, but can optionally pass in more columns to receive.
23
+ *
24
+ * @param array $columns
25
+ * @return \Fleetbase\Models\Storefront\Network|\Fleetbase\Models\Storefront\Store
26
+ */
27
+ public static function about($columns = [], $with = [])
28
+ {
29
+ $key = session('storefront_key');
30
+
31
+ if (!$key) {
32
+ return null;
33
+ }
34
+
35
+ if (is_array($columns)) {
36
+ $columns = array_merge(['uuid', 'public_id', 'company_uuid', 'backdrop_uuid', 'logo_uuid', 'name', 'description', 'translations', 'website', 'facebook', 'instagram', 'twitter', 'email', 'phone', 'tags', 'currency', 'timezone', 'pod_method', 'options'], $columns);
37
+ }
38
+
39
+ if (Str::startsWith($key, 'store')) {
40
+ $about = Store::select($columns)->where('key', $key)->with($with)->first();
41
+ } else {
42
+ $about = Network::select($columns)->where('key', $key)->with($with)->first();
43
+ }
44
+
45
+ $about->is_store = Str::startsWith($key, 'store');
46
+ $about->is_network = Str::startsWith($key, 'network');
47
+
48
+ return $about;
49
+ }
50
+
51
+ public static function findAbout($id, $columns = [], $with = [])
52
+ {
53
+ if (is_array($columns)) {
54
+ $columns = array_merge(['uuid', 'public_id', 'company_uuid', 'backdrop_uuid', 'logo_uuid', 'name', 'description', 'translations', 'website', 'facebook', 'instagram', 'twitter', 'email', 'phone', 'tags', 'currency', 'timezone', 'pod_method', 'options'], $columns);
55
+ }
56
+
57
+ if (Str::startsWith($id, 'store')) {
58
+ $about = Store::select($columns)->where('public_id', $id)->with($with)->first();
59
+ } else {
60
+ $about = Network::select($columns)->where('public_id', $id)->with($with)->first();
61
+ }
62
+
63
+ if (!$about) {
64
+ return $about;
65
+ }
66
+
67
+ $about->is_store = Str::startsWith($id, 'store');
68
+ $about->is_network = Str::startsWith($id, 'network');
69
+
70
+ return $about;
71
+ }
72
+
73
+ public static function getStoreFromLocation(string $id, $columns = [], $with = [])
74
+ {
75
+ if (is_array($columns)) {
76
+ $columns = array_merge(['uuid', 'public_id', 'company_uuid', 'backdrop_uuid', 'logo_uuid', 'name', 'description', 'translations', 'website', 'facebook', 'instagram', 'twitter', 'email', 'phone', 'tags', 'currency', 'timezone', 'pod_method', 'options'], $columns);
77
+ }
78
+
79
+ return Store::select($columns)->with($with)->whereHas('locations', function ($q) use ($id) {
80
+ $q->where('place_uuid', $id);
81
+ $q->orWhereHas('place', function ($q) use ($id) {
82
+ $q->where('public_id', $id);
83
+ });
84
+ })->first();
85
+ }
86
+
87
+ public static function getCustomerFromToken()
88
+ {
89
+ $token = request()->header('Customer-Token');
90
+
91
+ if ($token) {
92
+ $accessToken = PersonalAccessToken::findToken($token);
93
+
94
+ if ($accessToken && Utils::isUuid($accessToken->name)) {
95
+ $customer = Contact::where('uuid', $accessToken->name)->first();
96
+
97
+ if ($customer) {
98
+ return $customer;
99
+ }
100
+ }
101
+
102
+ if ($accessToken) {
103
+ return Contact::where('user_uuid', $accessToken->tokenable->uuid)->first();
104
+ }
105
+ }
106
+
107
+ return null;
108
+ }
109
+
110
+ public static function findGateway(string $code): ?Gateway
111
+ {
112
+ if ($code === 'cash') {
113
+ return Gateway::cash();
114
+ }
115
+
116
+ return Gateway::where([
117
+ 'code' => $code,
118
+ 'owner_uuid' => session('storefront_store') ?? session('storefront_network'),
119
+ ])->first();
120
+ }
121
+
122
+ public static function getFullDescriptionFromCartItem($cartItem)
123
+ {
124
+ $fullDescription = $cartItem->name;
125
+
126
+ if (is_array($cartItem->variants) && count($cartItem->variants)) {
127
+ $fullDescription .= ' with Variation: ';
128
+ $fullDescription .= collect($cartItem->variants)->pluck('name')->join(',');
129
+ }
130
+
131
+ if (is_array($cartItem->addons) && count($cartItem->addons)) {
132
+ $fullDescription .= ' with Addons: ';
133
+ $fullDescription .= collect($cartItem->addons)->pluck('name')->join(',');
134
+ }
135
+
136
+ return $fullDescription;
137
+ }
138
+
139
+ public static function destroyCart($cartId)
140
+ {
141
+ $prefix = 'cart:' . session('storefront_store') . ':';
142
+
143
+ return Redis::del($prefix . $cartId);
144
+ }
145
+
146
+ public static function getProduct($publicId)
147
+ {
148
+ return Product::select(['uuid', 'public_id', 'name', 'description', 'price', 'sale_price', 'is_on_sale'])->where(['public_id' => $publicId])->with([])->first();
149
+ }
150
+
151
+ public static function alertNewOrder(Order $order, $sendNow = false)
152
+ {
153
+ $about = static::about(['alertable']);
154
+ $alertables = [];
155
+
156
+ if ($about->is_network) {
157
+ $store = static::findAbout($order->getMeta('storefront_id'), ['alertable']);
158
+
159
+ if ($store && $store->public_id !== $about->public_id) {
160
+ $merge = Utils::get($store, 'alertable.for_new_order', []);
161
+ $alertables = array_merge($alertables, $merge);
162
+ }
163
+ }
164
+
165
+ $merge = Utils::get($about, 'alertable.for_new_order', []);
166
+ $alertables = array_merge($alertables, $merge);
167
+ $users = collect($alertables)->map(function ($id) {
168
+ return User::where('public_id', $id)->first();
169
+ });
170
+
171
+ if ($users->isEmpty()) {
172
+ return;
173
+ }
174
+
175
+ if ($sendNow) {
176
+ return Notification::sendNow($users, new StorefrontOrderCreated($order));
177
+ }
178
+
179
+ return Notification::send($users, new StorefrontOrderCreated($order));
180
+ }
181
+
182
+ public static function createStripeCustomerForContact(Contact &$customer)
183
+ {
184
+ $stripeCustomer = \Stripe\Customer::create([
185
+ 'description' => 'Customer created in Fleetbase Storefront',
186
+ 'email' => $customer->email,
187
+ 'name' => $customer->name,
188
+ 'phone' => $customer->phone,
189
+ 'metadata' => [
190
+ 'contact_id' => $customer->public_id,
191
+ 'storefront_id' => session('storefront_store') ?? session('storefront_network'),
192
+ 'company_id' => session('company')
193
+ ]
194
+ ]);
195
+
196
+ // set the stripe customer to customer meta
197
+ $customer->updateMeta('stripe_id', $stripeCustomer->id);
198
+
199
+ return $stripeCustomer;
200
+ }
201
+ }