@fleetbase/storefront-engine 0.3.17 → 0.3.20

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 (102) hide show
  1. package/addon/components/customer-panel/orders.hbs +107 -104
  2. package/addon/components/customer-panel/orders.js +52 -45
  3. package/addon/components/modals/incoming-order.hbs +208 -199
  4. package/addon/components/modals/manage-addons.js +6 -2
  5. package/addon/components/modals/order-ready-assign-driver.hbs +1 -1
  6. package/addon/components/order-panel/details.js +0 -2
  7. package/addon/components/order-panel.hbs +314 -1
  8. package/addon/components/order-panel.js +51 -3
  9. package/addon/components/widget/customers.hbs +75 -51
  10. package/addon/components/widget/customers.js +29 -41
  11. package/addon/components/widget/orders.hbs +278 -119
  12. package/addon/components/widget/orders.js +75 -80
  13. package/addon/components/widget/storefront-metrics.hbs +3 -6
  14. package/addon/components/widget/storefront-metrics.js +25 -41
  15. package/addon/controllers/orders/index.js +214 -105
  16. package/addon/controllers/products/index/category/new.js +2 -1
  17. package/addon/controllers/products/index/index.js +0 -23
  18. package/addon/controllers/settings/gateways.js +14 -18
  19. package/addon/helpers/get-tip-amount.js +13 -2
  20. package/addon/models/product-addon-category.js +3 -0
  21. package/addon/routes/application.js +2 -4
  22. package/addon/services/order-actions.js +248 -0
  23. package/addon/services/storefront.js +2 -0
  24. package/addon/styles/storefront-engine.css +55 -0
  25. package/addon/templates/home.hbs +2 -1
  26. package/addon/templates/orders/index/view.hbs +1 -1
  27. package/addon/templates/orders/index.hbs +26 -3
  28. package/addon/templates/products/index/category/new.hbs +4 -1
  29. package/addon/templates/products/index/index.hbs +28 -28
  30. package/addon/templates/settings/gateways.hbs +1 -1
  31. package/addon/templates/settings/index.hbs +2 -2
  32. package/addon/templates/settings.hbs +1 -1
  33. package/app/services/order-actions.js +1 -0
  34. package/composer.json +1 -1
  35. package/extension.json +1 -1
  36. package/package.json +1 -1
  37. package/server/migrations/2023_05_03_025307_create_carts_table.php +1 -1
  38. package/server/migrations/2023_05_03_025307_create_checkouts_table.php +1 -1
  39. package/server/migrations/2023_05_03_025307_create_gateways_table.php +1 -1
  40. package/server/migrations/2023_05_03_025307_create_network_stores_table.php +1 -1
  41. package/server/migrations/2023_05_03_025307_create_networks_table.php +1 -1
  42. package/server/migrations/2023_05_03_025307_create_notification_channels_table.php +1 -1
  43. package/server/migrations/2023_05_03_025307_create_payment_methods_table.php +1 -1
  44. package/server/migrations/2023_05_03_025307_create_product_addon_categories_table.php +1 -1
  45. package/server/migrations/2023_05_03_025307_create_product_addons_table.php +1 -1
  46. package/server/migrations/2023_05_03_025307_create_product_hours_table.php +1 -1
  47. package/server/migrations/2023_05_03_025307_create_product_store_locations_table.php +1 -1
  48. package/server/migrations/2023_05_03_025307_create_product_variant_options_table.php +1 -1
  49. package/server/migrations/2023_05_03_025307_create_product_variants_table.php +1 -1
  50. package/server/migrations/2023_05_03_025307_create_products_table.php +1 -1
  51. package/server/migrations/2023_05_03_025307_create_reviews_table.php +1 -1
  52. package/server/migrations/2023_05_03_025307_create_store_hours_table.php +1 -1
  53. package/server/migrations/2023_05_03_025307_create_store_locations_table.php +1 -1
  54. package/server/migrations/2023_05_03_025307_create_stores_table.php +1 -1
  55. package/server/migrations/2023_05_03_025307_create_votes_table.php +1 -1
  56. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_carts_table.php +1 -1
  57. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_checkouts_table.php +1 -1
  58. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_gateways_table.php +1 -1
  59. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_network_stores_table.php +1 -1
  60. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_networks_table.php +1 -1
  61. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_notification_channels_table.php +1 -1
  62. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_payment_methods_table.php +1 -1
  63. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_addon_categories_table.php +1 -1
  64. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_addons_table.php +1 -1
  65. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_hours_table.php +1 -1
  66. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_store_locations_table.php +1 -1
  67. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_variant_options_table.php +1 -1
  68. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_variants_table.php +1 -1
  69. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_products_table.php +1 -1
  70. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_reviews_table.php +1 -1
  71. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_store_hours_table.php +1 -1
  72. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_store_locations_table.php +1 -1
  73. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_stores_table.php +1 -1
  74. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_votes_table.php +1 -1
  75. package/server/src/Http/Controllers/ActionController.php +2 -1
  76. package/server/src/Http/Controllers/OrderController.php +15 -2
  77. package/server/src/Http/Controllers/ProductController.php +2 -0
  78. package/server/src/Http/Controllers/v1/CheckoutController.php +337 -40
  79. package/server/src/Http/Controllers/v1/CustomerController.php +88 -3
  80. package/server/src/Http/Controllers/v1/ServiceQuoteController.php +5 -5
  81. package/server/src/Http/Controllers/v1/StoreController.php +35 -5
  82. package/server/src/Http/Requests/CreateCustomerRequest.php +4 -0
  83. package/server/src/Http/Requests/CreateStripeSetupIntentRequest.php +31 -0
  84. package/server/src/Http/Requests/CustomerRequest.php +31 -0
  85. package/server/src/Http/Requests/InitializeCheckoutRequest.php +2 -1
  86. package/server/src/Http/Resources/Cart.php +18 -1
  87. package/server/src/Http/Resources/Customer.php +19 -14
  88. package/server/src/Http/Resources/Store.php +5 -1
  89. package/server/src/Models/AddonCategory.php +14 -16
  90. package/server/src/Models/Cart.php +10 -5
  91. package/server/src/Models/Customer.php +2 -2
  92. package/server/src/Models/Gateway.php +9 -4
  93. package/server/src/Models/Product.php +9 -10
  94. package/server/src/Models/ProductAddonCategory.php +2 -0
  95. package/server/src/Models/Store.php +2 -2
  96. package/server/src/Observers/OrderObserver.php +7 -1
  97. package/server/src/Rules/IsValidLocation.php +2 -2
  98. package/server/src/Support/QPay.php +35 -1
  99. package/server/src/Support/Storefront.php +34 -0
  100. package/server/src/Support/StripeUtils.php +38 -0
  101. package/server/src/routes.php +19 -0
  102. package/translations/en-us.yaml +8 -2
@@ -2,6 +2,7 @@
2
2
 
3
3
  namespace Fleetbase\Storefront\Http\Controllers\v1;
4
4
 
5
+ use Fleetbase\FleetOps\Exceptions\UserAlreadyExistsException;
5
6
  use Fleetbase\FleetOps\Http\Requests\UpdateContactRequest;
6
7
  use Fleetbase\FleetOps\Http\Resources\v1\DeletedResource;
7
8
  use Fleetbase\FleetOps\Http\Resources\v1\Order as OrderResource;
@@ -174,7 +175,6 @@ class CustomerController extends Controller
174
175
 
175
176
  // verify code
176
177
  $isVerified = VerificationCode::where(['code' => $code, 'for' => 'storefront_create_customer', 'meta->identity' => $identity])->exists();
177
-
178
178
  if (!$isVerified) {
179
179
  return response()->error('Invalid verification code provided!');
180
180
  }
@@ -209,13 +209,21 @@ class CustomerController extends Controller
209
209
  ];
210
210
 
211
211
  // create the customer/contact
212
- $customer = Contact::create($input);
212
+ try {
213
+ $customer = Contact::create($input);
214
+ } catch (UserAlreadyExistsException $e) {
215
+ // If the exception is thrown because user already exists and
216
+ // that user is the same user already assigned continue
217
+ $customer = Contact::where(['company_uuid' => session('company'), 'phone' => $input['phone']])->first();
218
+ } catch (\Exception $e) {
219
+ return response()->apiError($e->getMessage());
220
+ }
213
221
 
214
222
  // generate auth token
215
223
  try {
216
224
  $token = $user->createToken($customer->uuid);
217
225
  } catch (\Exception $e) {
218
- return response()->error($e->getMessage());
226
+ return response()->apiError($e->getMessage());
219
227
  }
220
228
 
221
229
  $customer->token = $token->plainTextToken;
@@ -251,6 +259,14 @@ class CustomerController extends Controller
251
259
  // always customer type
252
260
  $input['type'] = 'customer';
253
261
 
262
+ // If setting a default location for the contact
263
+ if ($request->has('place')) {
264
+ $input['place_uuid'] = Utils::getUuid('places', [
265
+ 'public_id' => $request->input('place'),
266
+ 'company_uuid' => session('company'),
267
+ ]);
268
+ }
269
+
254
270
  // update the contact
255
271
  $contact->update($input);
256
272
 
@@ -474,4 +490,73 @@ class CustomerController extends Controller
474
490
 
475
491
  return $phone;
476
492
  }
493
+
494
+ public function getStripeEphemeralKey(Request $request)
495
+ {
496
+ $customer = Storefront::getCustomerFromToken();
497
+ if (!$customer) {
498
+ return response()->error('Not authorized to view customers places');
499
+ }
500
+
501
+ $gateway = Storefront::findGateway('stripe');
502
+ if (!$gateway) {
503
+ return response()->apiError('Stripe not setup.');
504
+ }
505
+
506
+ \Stripe\Stripe::setApiKey($gateway->config->secret_key);
507
+
508
+ // Ensure customer has a stripe_id
509
+ if ($customer->missingMeta('stripe_id')) {
510
+ Storefront::createStripeCustomerForContact($customer);
511
+ }
512
+
513
+ try {
514
+ // Create Ephemeral Key
515
+ $ephemeralKey = \Stripe\EphemeralKey::create(
516
+ ['customer' => $customer->getMeta('stripe_id')],
517
+ ['stripe_version' => '2020-08-27']
518
+ );
519
+
520
+ return response()->json([
521
+ 'ephemeralKey' => $ephemeralKey->secret,
522
+ 'customer' => $customer->getMeta('stripe_id'),
523
+ ]);
524
+ } catch (\Exception $e) {
525
+ return response()->apiError($e->getMessage());
526
+ }
527
+ }
528
+
529
+ public function getStripeSetupIntent(Request $request)
530
+ {
531
+ $customer = Storefront::getCustomerFromToken();
532
+ if (!$customer) {
533
+ return response()->error('Not authorized to view customers places');
534
+ }
535
+
536
+ $gateway = Storefront::findGateway('stripe');
537
+ if (!$gateway) {
538
+ return response()->apiError('Stripe not setup.');
539
+ }
540
+
541
+ \Stripe\Stripe::setApiKey($gateway->config->secret_key);
542
+
543
+ // Ensure customer has a stripe_id
544
+ if ($customer->missingMeta('stripe_id')) {
545
+ Storefront::createStripeCustomerForContact($customer);
546
+ }
547
+
548
+ try {
549
+ // Create SetupIntent
550
+ $setupIntent = \Stripe\SetupIntent::create([
551
+ 'customer' => $customer->getMeta('stripe_id'),
552
+ ]);
553
+
554
+ return response()->json([
555
+ 'setupIntentId' => $setupIntent->id,
556
+ 'setupIntent' => $setupIntent->client_secret,
557
+ ]);
558
+ } catch (\Exception $e) {
559
+ return response()->apiError($e->getMessage());
560
+ }
561
+ }
477
562
  }
@@ -371,13 +371,13 @@ class ServiceQuoteController extends Controller
371
371
 
372
372
  /**
373
373
  * Returns a place from either a place id or store location id.
374
- *
375
- * @param string $id
376
- *
377
- * @return Place
378
374
  */
379
- public function getPlaceFromId($id)
375
+ public function getPlaceFromId(string|array $id): ?Place
380
376
  {
377
+ if (is_array($id)) {
378
+ $id = implode(',', $id);
379
+ }
380
+
381
381
  if (Str::startsWith($id, 'store_location')) {
382
382
  $storeLocation = StoreLocation::select(['place_uuid'])->where(['public_id' => $id, 'store_uuid' => session('storefront_store')])->with(['place'])->first();
383
383
 
@@ -4,11 +4,12 @@ namespace Fleetbase\Storefront\Http\Controllers\v1;
4
4
 
5
5
  use Fleetbase\Http\Controllers\Controller;
6
6
  use Fleetbase\Storefront\Http\Resources\Gateway as GatewayResource;
7
- use Fleetbase\Storefront\Http\Resources\Network;
7
+ use Fleetbase\Storefront\Http\Resources\Network as NetworkResource;
8
8
  use Fleetbase\Storefront\Http\Resources\Product as ProductResource;
9
- use Fleetbase\Storefront\Http\Resources\Store as StorefrontStore;
9
+ use Fleetbase\Storefront\Http\Resources\Store as StorefrontResource;
10
10
  use Fleetbase\Storefront\Http\Resources\StoreLocation as StoreLocationResource;
11
11
  use Fleetbase\Storefront\Models\Gateway;
12
+ use Fleetbase\Storefront\Models\Network;
12
13
  use Fleetbase\Storefront\Models\Product;
13
14
  use Fleetbase\Storefront\Models\Store;
14
15
  use Fleetbase\Storefront\Models\StoreLocation;
@@ -32,10 +33,34 @@ class StoreController extends Controller
32
33
  }
33
34
 
34
35
  if ($about->is_store) {
35
- return new StorefrontStore($about);
36
+ return new StorefrontResource($about);
36
37
  }
37
38
 
38
- return new Network($about);
39
+ return new NetworkResource($about);
40
+ }
41
+
42
+ /**
43
+ * Lookup a store or network provided the ID.
44
+ *
45
+ * @return \Illuminate\Http\Response
46
+ */
47
+ public function lookup(?string $id)
48
+ {
49
+ if (!$id) {
50
+ return response()->apiError('No ID provided for lookup.');
51
+ }
52
+
53
+ $store = Store::where(['public_id' => $id, 'company_uuid' => session('company')])->first();
54
+ if ($store) {
55
+ return new StorefrontResource($store);
56
+ }
57
+
58
+ $network = Network::where(['public_id' => $id, 'company_uuid' => session('company')])->first();
59
+ if ($network) {
60
+ return new NetworkResource($network);
61
+ }
62
+
63
+ return response()->apiError('Unable to find store or network for ID provided.');
39
64
  }
40
65
 
41
66
  /**
@@ -125,7 +150,12 @@ class StoreController extends Controller
125
150
  $ownerId = session('storefront_store') ?? session('storefront_network');
126
151
 
127
152
  $sandbox = $request->input('sandbox', false);
128
- $query = Gateway::select(['public_id', 'name', 'code', 'type', 'sandbox', 'return_url', 'callback_url'])->where(['public_id' => $id, 'owner_uuid' => $ownerId]);
153
+ $query = Gateway::select(['public_id', 'name', 'code', 'type', 'sandbox', 'return_url', 'callback_url'])
154
+ ->where(['owner_uuid' => $ownerId])
155
+ ->where(function ($q) use ($id) {
156
+ $q->where('public_id', $id);
157
+ $q->orWhere('code', $id);
158
+ });
129
159
 
130
160
  if ($sandbox) {
131
161
  $query->where('sandbox', 1);
@@ -29,11 +29,15 @@ class CreateCustomerRequest extends FleetbaseRequest
29
29
  'name' => 'required',
30
30
  'email' => [
31
31
  'email', 'nullable', Rule::unique('contacts')->where(function ($query) {
32
+ $query->where('company_uuid', session('company'));
33
+
32
34
  return $query->whereNull('deleted_at');
33
35
  }),
34
36
  ],
35
37
  'phone' => [
36
38
  'nullable', Rule::unique('contacts')->where(function ($query) {
39
+ $query->where('company_uuid', session('company'));
40
+
37
41
  return $query->whereNull('deleted_at');
38
42
  }),
39
43
  ],
@@ -0,0 +1,31 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\Storefront\Http\Requests;
4
+
5
+ use Fleetbase\Http\Requests\FleetbaseRequest;
6
+ use Fleetbase\Storefront\Rules\CustomerExists;
7
+
8
+ class CreateStripeSetupIntentRequest extends FleetbaseRequest
9
+ {
10
+ /**
11
+ * Determine if the user is authorized to make this request.
12
+ *
13
+ * @return bool
14
+ */
15
+ public function authorize()
16
+ {
17
+ return session('storefront_key');
18
+ }
19
+
20
+ /**
21
+ * Get the validation rules that apply to the request.
22
+ *
23
+ * @return array
24
+ */
25
+ public function rules()
26
+ {
27
+ return [
28
+ 'customer' => ['required', new CustomerExists()],
29
+ ];
30
+ }
31
+ }
@@ -0,0 +1,31 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\Storefront\Http\Requests;
4
+
5
+ use Fleetbase\Http\Requests\FleetbaseRequest;
6
+ use Fleetbase\Storefront\Rules\CustomerExists;
7
+
8
+ class CustomerRequest extends FleetbaseRequest
9
+ {
10
+ /**
11
+ * Determine if the user is authorized to make this request.
12
+ *
13
+ * @return bool
14
+ */
15
+ public function authorize()
16
+ {
17
+ return session('storefront_key');
18
+ }
19
+
20
+ /**
21
+ * Get the validation rules that apply to the request.
22
+ *
23
+ * @return array
24
+ */
25
+ public function rules()
26
+ {
27
+ return [
28
+ 'customer' => ['required', new CustomerExists()],
29
+ ];
30
+ }
31
+ }
@@ -5,6 +5,7 @@ namespace Fleetbase\Storefront\Http\Requests;
5
5
  use Fleetbase\Http\Requests\FleetbaseRequest;
6
6
  use Fleetbase\Storefront\Rules\CustomerExists;
7
7
  use Fleetbase\Storefront\Rules\GatewayExists;
8
+ use Illuminate\Validation\Rule;
8
9
 
9
10
  class InitializeCheckoutRequest extends FleetbaseRequest
10
11
  {
@@ -29,7 +30,7 @@ class InitializeCheckoutRequest extends FleetbaseRequest
29
30
  'gateway' => ['required', new GatewayExists()],
30
31
  'customer' => ['required', new CustomerExists()],
31
32
  'cart' => ['required', 'exists:storefront.carts,public_id'],
32
- 'serviceQuote' => ['required', 'exists:service_quotes,public_id'],
33
+ 'serviceQuote' => [Rule::requiredIf(fn () => !$this->boolean('pickup')), 'exists:service_quotes,public_id'],
33
34
  'cash' => ['sometimes', 'boolean'],
34
35
  'pickup' => ['sometimes', 'boolean'],
35
36
  ];
@@ -3,6 +3,7 @@
3
3
  namespace Fleetbase\Storefront\Http\Resources;
4
4
 
5
5
  use Fleetbase\Http\Resources\FleetbaseResource;
6
+ use Fleetbase\Storefront\Models\Product;
6
7
  use Fleetbase\Support\Http;
7
8
 
8
9
  class Cart extends FleetbaseResource
@@ -29,7 +30,7 @@ class Cart extends FleetbaseResource
29
30
  'subtotal' => $this->subtotal,
30
31
  'total_items' => $this->total_items,
31
32
  'total_unique_items' => $this->total_unique_items,
32
- 'items' => $this->items ?? [],
33
+ 'items' => $this->getCartItems(),
33
34
  'events' => $this->events ?? [],
34
35
  'discount_code' => $this->discount_code,
35
36
  'expires_at' => $this->expires_at,
@@ -37,4 +38,20 @@ class Cart extends FleetbaseResource
37
38
  'updated_at' => $this->updated_at,
38
39
  ];
39
40
  }
41
+
42
+ public function getCartItems()
43
+ {
44
+ $items = $this->items ?? [];
45
+
46
+ return array_map(function ($cartItem) {
47
+ $product = Product::select(['public_id', 'primary_image_uuid', 'name', 'description'])->where('public_id', data_get($cartItem, 'product_id'))->first();
48
+ if ($product) {
49
+ data_set($cartItem, 'name', $product->name);
50
+ data_set($cartItem, 'description', $product->description);
51
+ data_set($cartItem, 'product_image_url', $product->primary_image_url);
52
+ }
53
+
54
+ return $cartItem;
55
+ }, $items);
56
+ }
40
57
  }
@@ -2,6 +2,7 @@
2
2
 
3
3
  namespace Fleetbase\Storefront\Http\Resources;
4
4
 
5
+ use Fleetbase\FleetOps\Http\Resources\v1\Place;
5
6
  use Fleetbase\Http\Resources\FleetbaseResource;
6
7
  use Fleetbase\Support\Http;
7
8
  use Illuminate\Support\Str;
@@ -17,21 +18,25 @@ class Customer extends FleetbaseResource
17
18
  */
18
19
  public function toArray($request)
19
20
  {
21
+ $this->loadMissing(['place', 'places']);
22
+
20
23
  return [
21
- 'id' => $this->when(Http::isInternalRequest(), $this->id, Str::replaceFirst('contact', 'customer', $this->public_id)),
22
- 'uuid' => $this->when(Http::isInternalRequest(), $this->uuid),
23
- 'public_id' => $this->when(Http::isInternalRequest(), $this->public_id),
24
- 'internal_id' => $this->internal_id,
25
- 'name' => $this->name,
26
- 'photo_url' => $this->photo_url,
27
- 'email' => $this->email,
28
- 'phone' => $this->phone,
29
- 'address' => data_get($this, 'address.address'),
30
- 'addresses' => $this->addresses,
31
- 'token' => $this->when($this->token, $this->token),
32
- 'slug' => $this->slug,
33
- 'created_at' => $this->created_at,
34
- 'updated_at' => $this->updated_at,
24
+ 'id' => $this->when(Http::isInternalRequest(), $this->id, Str::replaceFirst('contact', 'customer', $this->public_id)),
25
+ 'uuid' => $this->when(Http::isInternalRequest(), $this->uuid),
26
+ 'public_id' => $this->when(Http::isInternalRequest(), $this->public_id),
27
+ 'address_id' => $this->place ? $this->place->public_id : null,
28
+ 'internal_id' => $this->internal_id,
29
+ 'name' => $this->name,
30
+ 'photo_url' => $this->photo_url,
31
+ 'email' => $this->email,
32
+ 'phone' => $this->phone,
33
+ 'address' => data_get($this, 'place.address'),
34
+ 'addresses' => $this->whenLoaded('places', Place::collection($this->places)),
35
+ 'token' => $this->when($this->token, $this->token),
36
+ 'meta' => $this->meta ?? [],
37
+ 'slug' => $this->slug,
38
+ 'created_at' => $this->created_at,
39
+ 'updated_at' => $this->updated_at,
35
40
  ];
36
41
  }
37
42
  }
@@ -4,6 +4,7 @@ namespace Fleetbase\Storefront\Http\Resources;
4
4
 
5
5
  use Fleetbase\Http\Resources\FleetbaseResource;
6
6
  use Fleetbase\Support\Http;
7
+ use Fleetbase\Support\Utils;
7
8
 
8
9
  class Store extends FleetbaseResource
9
10
  {
@@ -16,6 +17,8 @@ class Store extends FleetbaseResource
16
17
  */
17
18
  public function toArray($request)
18
19
  {
20
+ $currency = $this->currency ?? 'USD';
21
+
19
22
  return [
20
23
  'id' => $this->when(Http::isInternalRequest(), $this->id, $this->public_id),
21
24
  'uuid' => $this->when(Http::isInternalRequest(), $this->uuid),
@@ -35,7 +38,8 @@ class Store extends FleetbaseResource
35
38
  'email' => $this->email,
36
39
  'phone' => $this->phone,
37
40
  'tags' => $this->tags ?? [],
38
- 'currency' => $this->currency ?? 'USD',
41
+ 'currency' => $currency,
42
+ 'country' => Utils::getCountryCodeByCurrency($currency, 'US'),
39
43
  'options' => $this->formatOptions($this->options),
40
44
  'logo_url' => $this->logo_url,
41
45
  'backdrop_url' => $this->backdrop_url,
@@ -2,8 +2,8 @@
2
2
 
3
3
  namespace Fleetbase\Storefront\Models;
4
4
 
5
+ use Fleetbase\Casts\Money as MoneyCast;
5
6
  use Fleetbase\Models\Category;
6
- use Illuminate\Support\Arr;
7
7
  use Illuminate\Support\Str;
8
8
 
9
9
  class AddonCategory extends Category
@@ -34,29 +34,27 @@ class AddonCategory extends Category
34
34
  // get uuid if set
35
35
  $id = data_get($addon, 'uuid');
36
36
 
37
- // make sure the cateogry is set to this current
38
- data_set($addon, 'category_uuid', $this->uuid);
39
-
40
- // make sure sale price is 0 if null
41
- if (data_get($addon, 'sale_price') === null) {
42
- data_set($addon, 'sale_price', 0);
43
- }
37
+ // create an upsertable array
38
+ $upsertableProductAddon = [
39
+ 'category_uuid' => $this->uuid,
40
+ 'name' => data_get($addon, 'name'),
41
+ 'description' => data_get($addon, 'description'),
42
+ 'translations' => data_get($addon, 'translations', []),
43
+ 'price' => MoneyCast::apply($addon['price'] ?? 0),
44
+ 'sale_price' => MoneyCast::apply($addon['sale_price'] ?? 0),
45
+ 'is_on_sale' => data_get($addon, 'is_on_sale'),
46
+ ];
44
47
 
45
48
  // update product addon category
46
49
  if (Str::isUuid($id)) {
47
- ProductAddon::where('uuid', $id)->update(Arr::except($addon, ['uuid', 'created_at', 'updated_at']));
50
+ ProductAddon::where('uuid', $id)->update($upsertableProductAddon);
48
51
  continue;
49
52
  }
50
53
 
51
54
  // create new product addon category
52
55
  ProductAddon::create([
53
- 'category_uuid' => $this->uuid,
54
- 'name' => data_get($addon, 'name'),
55
- 'description' => data_get($addon, 'description'),
56
- 'translations' => data_get($addon, 'translations', []),
57
- 'price' => data_get($addon, 'price'),
58
- 'sale_price' => data_get($addon, 'sale_price'),
59
- 'is_on_sale' => data_get($addon, 'is_on_sale'),
56
+ ...$upsertableProductAddon,
57
+ 'created_by_uuid' => session('user'),
60
58
  ]);
61
59
  }
62
60
 
@@ -5,6 +5,7 @@ namespace Fleetbase\Storefront\Models;
5
5
  use Fleetbase\FleetOps\Models\Contact;
6
6
  use Fleetbase\FleetOps\Support\Utils;
7
7
  use Fleetbase\Models\Company;
8
+ use Fleetbase\Models\User;
8
9
  use Fleetbase\Traits\Expirable;
9
10
  use Fleetbase\Traits\HasApiModelBehavior;
10
11
  use Fleetbase\Traits\HasPublicId;
@@ -294,11 +295,10 @@ class Cart extends StorefrontModel
294
295
  /**
295
296
  * Adds an item to cart.
296
297
  *
297
- * @param \Fleetbase\Models\Storefront\Product $product
298
- * @param int $quantity
299
- * @param array $variants
300
- * @param array $addons
301
- * @param string $createdAt
298
+ * @param int $quantity
299
+ * @param array $variants
300
+ * @param array $addons
301
+ * @param string $createdAt
302
302
  */
303
303
  public function addItem(Product $product, $quantity = 1, $variants = [], $addons = [], $storeLocationId = null, $scheduledAt = null, $createdAt = null)
304
304
  {
@@ -673,4 +673,9 @@ class Cart extends StorefrontModel
673
673
  {
674
674
  return Product::select(['uuid', 'store_uuid', 'public_id', 'name', 'description', 'price', 'currency', 'sale_price', 'is_on_sale'])->where(['public_id' => $id])->with([])->first();
675
675
  }
676
+
677
+ public function getCurrency(?string $fallbackCurrency = null): ?string
678
+ {
679
+ return $this->currency ?? session('storefront_currency', $fallbackCurrency);
680
+ }
676
681
  }
@@ -75,9 +75,9 @@ class Customer extends Contact
75
75
  *
76
76
  * @param string $publicId The public ID of the customer to find
77
77
  *
78
- * @return static|null The customer with the given public ID, or null if none was found
78
+ * @return Customer|null The customer with the given public ID, or null if none was found
79
79
  */
80
- public static function findFromCustomerId($publicId)
80
+ public static function findFromCustomerId($publicId): self
81
81
  {
82
82
  if (Str::startsWith($publicId, 'customer')) {
83
83
  $publicId = Str::replaceFirst('customer', 'contact', $publicId);
@@ -136,14 +136,19 @@ class Gateway extends StorefrontModel
136
136
  return (object) $sortedConfig;
137
137
  }
138
138
 
139
- public function getIsStripeGatewayAttribute()
139
+ public function getIsStripeGatewayAttribute(): bool
140
140
  {
141
- return $this->type === 'stripe';
141
+ return $this->isGateway('stripe');
142
142
  }
143
143
 
144
- public function getIsQpayGatewayAttribute()
144
+ public function getIsQPayGatewayAttribute(): bool
145
145
  {
146
- return $this->type === 'qpay';
146
+ return $this->isGateway('qpay');
147
+ }
148
+
149
+ public function isGateway(string $type): bool
150
+ {
151
+ return strtolower($this->type) === strtolower($type);
147
152
  }
148
153
 
149
154
  /**
@@ -305,23 +305,22 @@ class Product extends StorefrontModel
305
305
  // get uuid if set
306
306
  $id = data_get($addonCategory, 'uuid');
307
307
 
308
- // Make sure product is set
309
- data_set($addonCategory, 'product_uuid', $this->uuid);
308
+ $upsertableAddonCategory = [
309
+ 'product_uuid' => $this->uuid,
310
+ 'category_uuid' => data_get($addonCategory, 'category_uuid'),
311
+ 'excluded_addons' => data_get($addonCategory, 'excluded_addons'),
312
+ 'max_selectable' => data_get($addonCategory, 'max_selectable'),
313
+ 'is_required' => data_get($addonCategory, 'is_required'),
314
+ ];
310
315
 
311
316
  // update product addon category
312
317
  if (Str::isUuid($id)) {
313
- ProductAddonCategory::where('uuid', $id)->update(Arr::except($addonCategory, ['uuid', 'created_at', 'updated_at', 'name', 'category']));
318
+ ProductAddonCategory::where('uuid', $id)->update($upsertableAddonCategory);
314
319
  continue;
315
320
  }
316
321
 
317
322
  // create new product addon category
318
- ProductAddonCategory::create([
319
- 'product_uuid' => $this->uuid,
320
- 'category_uuid' => data_get($addonCategory, 'category_uuid'),
321
- 'excluded_addons' => data_get($addonCategory, 'excluded_addons'),
322
- 'max_selectable' => data_get($addonCategory, 'max_selectable'),
323
- 'is_required' => data_get($addonCategory, 'is_required'),
324
- ]);
323
+ ProductAddonCategory::create($upsertableAddonCategory);
325
324
  }
326
325
 
327
326
  return $this;
@@ -35,6 +35,7 @@ class ProductAddonCategory extends StorefrontModel
35
35
  'category_uuid',
36
36
  'excluded_addons',
37
37
  'max_selectable',
38
+ 'is_required',
38
39
  ];
39
40
 
40
41
  /**
@@ -44,6 +45,7 @@ class ProductAddonCategory extends StorefrontModel
44
45
  */
45
46
  protected $casts = [
46
47
  'excluded_addons' => Json::class,
48
+ 'is_required' => 'boolean',
47
49
  ];
48
50
 
49
51
  /**
@@ -310,7 +310,7 @@ class Store extends StorefrontModel
310
310
  *
311
311
  * @param string $id the ID of the network for which the category is to be retrieved
312
312
  *
313
- * @return \Fleetbase\Models\Category|null the category of the store in the given network, or null if the store does not belong to the network
313
+ * @return Category|null the category of the store in the given network, or null if the store does not belong to the network
314
314
  */
315
315
  public function getNetworkCategoryUsingId(?string $id)
316
316
  {
@@ -334,7 +334,7 @@ class Store extends StorefrontModel
334
334
  *
335
335
  * @param Network $network the network for which the category is to be retrieved
336
336
  *
337
- * @return \Fleetbase\Models\Category|null the category of the store in the given network, or null if the store does not belong to the network
337
+ * @return Category|null the category of the store in the given network, or null if the store does not belong to the network
338
338
  */
339
339
  public function getNetworkCategory(Network $network)
340
340
  {
@@ -3,6 +3,7 @@
3
3
  namespace Fleetbase\Storefront\Observers;
4
4
 
5
5
  use Fleetbase\FleetOps\Models\Order;
6
+ use Fleetbase\Storefront\Support\Storefront;
6
7
 
7
8
  class OrderObserver
8
9
  {
@@ -11,7 +12,12 @@ class OrderObserver
11
12
  *
12
13
  * @return void
13
14
  */
14
- public function created(Order $order)
15
+ public function creating(Order $order)
15
16
  {
17
+ // Set the storefront order config
18
+ $orderConfig = Storefront::getDefaultOrderConfig();
19
+ if ($orderConfig) {
20
+ $order->order_config_uuid = $orderConfig->uuid;
21
+ }
16
22
  }
17
23
  }
@@ -20,12 +20,12 @@ class IsValidLocation implements Rule
20
20
  public function passes($attribute, $value)
21
21
  {
22
22
  // Validate Place id
23
- if (Str::startsWith($value, 'place_')) {
23
+ if (is_string($value) && Str::startsWith($value, 'place_')) {
24
24
  return Place::where('public_id', $value)->exists();
25
25
  }
26
26
 
27
27
  // Validate StoreLocation id
28
- if (Str::startsWith($value, 'store_location_')) {
28
+ if (is_string($value) && Str::startsWith($value, 'store_location_')) {
29
29
  return StoreLocation::where('public_id', $value)->exists();
30
30
  }
31
31