@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.
- package/addon/components/customer-panel/orders.hbs +107 -104
- package/addon/components/customer-panel/orders.js +52 -45
- package/addon/components/modals/incoming-order.hbs +208 -199
- package/addon/components/modals/manage-addons.js +6 -2
- package/addon/components/modals/order-ready-assign-driver.hbs +1 -1
- package/addon/components/order-panel/details.js +0 -2
- package/addon/components/order-panel.hbs +314 -1
- package/addon/components/order-panel.js +51 -3
- package/addon/components/widget/customers.hbs +75 -51
- package/addon/components/widget/customers.js +29 -41
- package/addon/components/widget/orders.hbs +278 -119
- package/addon/components/widget/orders.js +75 -80
- package/addon/components/widget/storefront-metrics.hbs +3 -6
- package/addon/components/widget/storefront-metrics.js +25 -41
- package/addon/controllers/orders/index.js +214 -105
- package/addon/controllers/products/index/category/new.js +2 -1
- package/addon/controllers/products/index/index.js +0 -23
- package/addon/controllers/settings/gateways.js +14 -18
- package/addon/helpers/get-tip-amount.js +13 -2
- package/addon/models/product-addon-category.js +3 -0
- package/addon/routes/application.js +2 -4
- package/addon/services/order-actions.js +248 -0
- package/addon/services/storefront.js +2 -0
- package/addon/styles/storefront-engine.css +55 -0
- package/addon/templates/home.hbs +2 -1
- package/addon/templates/orders/index/view.hbs +1 -1
- package/addon/templates/orders/index.hbs +26 -3
- package/addon/templates/products/index/category/new.hbs +4 -1
- package/addon/templates/products/index/index.hbs +28 -28
- package/addon/templates/settings/gateways.hbs +1 -1
- package/addon/templates/settings/index.hbs +2 -2
- package/addon/templates/settings.hbs +1 -1
- package/app/services/order-actions.js +1 -0
- package/composer.json +1 -1
- package/extension.json +1 -1
- package/package.json +1 -1
- package/server/migrations/2023_05_03_025307_create_carts_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_checkouts_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_gateways_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_network_stores_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_networks_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_notification_channels_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_payment_methods_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_product_addon_categories_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_product_addons_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_product_hours_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_product_store_locations_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_product_variant_options_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_product_variants_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_products_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_reviews_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_store_hours_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_store_locations_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_stores_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_votes_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_carts_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_checkouts_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_gateways_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_network_stores_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_networks_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_notification_channels_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_payment_methods_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_addon_categories_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_addons_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_hours_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_store_locations_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_variant_options_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_variants_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_products_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_reviews_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_store_hours_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_store_locations_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_stores_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_votes_table.php +1 -1
- package/server/src/Http/Controllers/ActionController.php +2 -1
- package/server/src/Http/Controllers/OrderController.php +15 -2
- package/server/src/Http/Controllers/ProductController.php +2 -0
- package/server/src/Http/Controllers/v1/CheckoutController.php +337 -40
- package/server/src/Http/Controllers/v1/CustomerController.php +88 -3
- package/server/src/Http/Controllers/v1/ServiceQuoteController.php +5 -5
- package/server/src/Http/Controllers/v1/StoreController.php +35 -5
- package/server/src/Http/Requests/CreateCustomerRequest.php +4 -0
- package/server/src/Http/Requests/CreateStripeSetupIntentRequest.php +31 -0
- package/server/src/Http/Requests/CustomerRequest.php +31 -0
- package/server/src/Http/Requests/InitializeCheckoutRequest.php +2 -1
- package/server/src/Http/Resources/Cart.php +18 -1
- package/server/src/Http/Resources/Customer.php +19 -14
- package/server/src/Http/Resources/Store.php +5 -1
- package/server/src/Models/AddonCategory.php +14 -16
- package/server/src/Models/Cart.php +10 -5
- package/server/src/Models/Customer.php +2 -2
- package/server/src/Models/Gateway.php +9 -4
- package/server/src/Models/Product.php +9 -10
- package/server/src/Models/ProductAddonCategory.php +2 -0
- package/server/src/Models/Store.php +2 -2
- package/server/src/Observers/OrderObserver.php +7 -1
- package/server/src/Rules/IsValidLocation.php +2 -2
- package/server/src/Support/QPay.php +35 -1
- package/server/src/Support/Storefront.php +34 -0
- package/server/src/Support/StripeUtils.php +38 -0
- package/server/src/routes.php +19 -0
- 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
|
-
|
|
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()->
|
|
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
|
|
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
|
|
36
|
+
return new StorefrontResource($about);
|
|
36
37
|
}
|
|
37
38
|
|
|
38
|
-
return new
|
|
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'])
|
|
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' => ['
|
|
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->
|
|
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'
|
|
22
|
-
'uuid'
|
|
23
|
-
'public_id'
|
|
24
|
-
'
|
|
25
|
-
'
|
|
26
|
-
'
|
|
27
|
-
'
|
|
28
|
-
'
|
|
29
|
-
'
|
|
30
|
-
'
|
|
31
|
-
'
|
|
32
|
-
'
|
|
33
|
-
'
|
|
34
|
-
'
|
|
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' => $
|
|
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
|
-
//
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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(
|
|
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
|
-
|
|
54
|
-
'
|
|
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
|
|
298
|
-
* @param
|
|
299
|
-
* @param array
|
|
300
|
-
* @param
|
|
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
|
|
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->
|
|
141
|
+
return $this->isGateway('stripe');
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
-
public function
|
|
144
|
+
public function getIsQPayGatewayAttribute(): bool
|
|
145
145
|
{
|
|
146
|
-
return $this->
|
|
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
|
-
|
|
309
|
-
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
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
|
|