@fleetbase/storefront-engine 0.4.11 → 0.4.13
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/composer.json +2 -2
- package/extension.json +1 -1
- package/package.json +1 -1
- package/server/src/Http/Controllers/v1/CheckoutController.php +276 -3
- package/server/src/Http/Controllers/v1/CustomerController.php +93 -2
- package/server/src/Http/Controllers/v1/ServiceQuoteController.php +14 -4
- package/server/src/Models/Checkout.php +1 -0
- package/server/src/routes.php +3 -0
package/composer.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fleetbase/storefront-api",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.13",
|
|
4
4
|
"description": "Headless Commerce & Marketplace Extension for Fleetbase",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"fleetbase-extension",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"milon/barcode": "^10.0",
|
|
32
32
|
"php-http/guzzle7-adapter": "^1.0",
|
|
33
33
|
"psr/http-factory-implementation": "*",
|
|
34
|
-
"stripe/stripe-php": "
|
|
34
|
+
"stripe/stripe-php": "^17.0",
|
|
35
35
|
"toin0u/geocoder-laravel": "^4.4"
|
|
36
36
|
},
|
|
37
37
|
"require-dev": {
|
package/extension.json
CHANGED
package/package.json
CHANGED
|
@@ -30,6 +30,7 @@ use Fleetbase\Storefront\Support\StripeUtils;
|
|
|
30
30
|
use Fleetbase\Support\SocketCluster\SocketClusterService;
|
|
31
31
|
use Illuminate\Http\Request;
|
|
32
32
|
use Illuminate\Support\Arr;
|
|
33
|
+
use Illuminate\Support\Facades\Cache;
|
|
33
34
|
use Illuminate\Support\Facades\Log;
|
|
34
35
|
use Illuminate\Support\Str;
|
|
35
36
|
use Stripe\Exception\InvalidRequestException;
|
|
@@ -641,7 +642,6 @@ class CheckoutController extends Controller
|
|
|
641
642
|
}
|
|
642
643
|
|
|
643
644
|
$paymentCheck = $qpay->paymentCheck($invoiceId);
|
|
644
|
-
|
|
645
645
|
if (!$paymentCheck || empty($paymentCheck->count) || $paymentCheck->count < 1) {
|
|
646
646
|
return response()->json([
|
|
647
647
|
'error' => 'PAYMENT_NOTFOUND',
|
|
@@ -651,7 +651,18 @@ class CheckoutController extends Controller
|
|
|
651
651
|
}
|
|
652
652
|
|
|
653
653
|
$payment = data_get($paymentCheck, 'rows.0');
|
|
654
|
+
|
|
654
655
|
if ($payment) {
|
|
656
|
+
// Create order from payment using reusable gateway-agnostic method
|
|
657
|
+
$transactionDetails = [
|
|
658
|
+
'transaction_id' => $payment->payment_id,
|
|
659
|
+
'payment_status' => 'PAID',
|
|
660
|
+
'payment_wallet' => $payment->payment_wallet ?? 'QPay',
|
|
661
|
+
];
|
|
662
|
+
|
|
663
|
+
$this->createOrderFromCheckout($checkout, $transactionDetails);
|
|
664
|
+
$checkout->refresh();
|
|
665
|
+
|
|
655
666
|
$data = [
|
|
656
667
|
'checkout' => $checkout->public_id,
|
|
657
668
|
'payment' => (array) $payment,
|
|
@@ -673,9 +684,116 @@ class CheckoutController extends Controller
|
|
|
673
684
|
}
|
|
674
685
|
|
|
675
686
|
/**
|
|
676
|
-
*
|
|
687
|
+
* Create order from checkout session.
|
|
688
|
+
*
|
|
689
|
+
* Gateway-agnostic reusable method to create an order from a checkout session.
|
|
690
|
+
* Works with any payment gateway (QPay, Stripe, etc.) by delegating to captureOrder().
|
|
691
|
+
* Handles idempotency by checking if order already exists.
|
|
692
|
+
*
|
|
693
|
+
* @param Checkout $checkout The checkout session
|
|
694
|
+
* @param array $transactionDetails Payment gateway transaction details
|
|
695
|
+
* @param string|null $notes Optional notes for the order
|
|
696
|
+
*
|
|
697
|
+
* @return Order|null The created order or null if already exists/error
|
|
698
|
+
*/
|
|
699
|
+
private function createOrderFromCheckout($checkout, $transactionDetails, $notes = null)
|
|
700
|
+
{
|
|
701
|
+
// Define a unique lock key for this specific checkout
|
|
702
|
+
$lockKey = 'create-order-checkout-' . $checkout->uuid;
|
|
703
|
+
|
|
704
|
+
// Attempt to acquire a lock for 10 seconds
|
|
705
|
+
$lock = Cache::lock($lockKey, 10);
|
|
706
|
+
|
|
707
|
+
if ($lock->get()) {
|
|
708
|
+
try {
|
|
709
|
+
// Re-fetch checkout to ensure we have the latest data after acquiring lock
|
|
710
|
+
$checkout->refresh();
|
|
711
|
+
|
|
712
|
+
// Check if order already exists for this checkout
|
|
713
|
+
if ($checkout->order_uuid) {
|
|
714
|
+
Log::info('[ORDER CREATION]: Order already exists for checkout after acquiring lock', [
|
|
715
|
+
'checkout_id' => $checkout->public_id,
|
|
716
|
+
'order_id' => $checkout->order_uuid,
|
|
717
|
+
]);
|
|
718
|
+
|
|
719
|
+
return $checkout->order;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
Log::info('[ORDER CREATION]: Creating order from payment', [
|
|
723
|
+
'checkout_id' => $checkout->public_id,
|
|
724
|
+
'transaction_id' => $transactionDetails['transaction_id'] ?? null,
|
|
725
|
+
]);
|
|
726
|
+
|
|
727
|
+
// Create CaptureOrderRequest with payment details
|
|
728
|
+
$captureRequest = CaptureOrderRequest::create('', 'POST', [
|
|
729
|
+
'token' => $checkout->token,
|
|
730
|
+
'transactionDetails' => $transactionDetails,
|
|
731
|
+
'notes' => $notes,
|
|
732
|
+
]);
|
|
733
|
+
|
|
734
|
+
// Call captureOrder to create the order
|
|
735
|
+
$this->captureOrder($captureRequest);
|
|
736
|
+
|
|
737
|
+
// Reload checkout to get the created order
|
|
738
|
+
$checkout->refresh();
|
|
739
|
+
|
|
740
|
+
if ($checkout->order) {
|
|
741
|
+
Log::info('[ORDER CREATION]: Order created successfully', [
|
|
742
|
+
'checkout_id' => $checkout->public_id,
|
|
743
|
+
'order_id' => $checkout->order->public_id,
|
|
744
|
+
]);
|
|
745
|
+
|
|
746
|
+
return $checkout->order;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
Log::warning('[ORDER CREATION]: captureOrder completed but no order found on checkout', [
|
|
750
|
+
'checkout_id' => $checkout->public_id,
|
|
751
|
+
]);
|
|
752
|
+
|
|
753
|
+
return null;
|
|
754
|
+
} catch (\Exception $e) {
|
|
755
|
+
Log::error('[ORDER CREATION ERROR]: ' . $e->getMessage(), [
|
|
756
|
+
'checkout_id' => $checkout->public_id,
|
|
757
|
+
'transaction_details' => $transactionDetails,
|
|
758
|
+
'exception' => $e->getTraceAsString(),
|
|
759
|
+
]);
|
|
760
|
+
|
|
761
|
+
return null;
|
|
762
|
+
} finally {
|
|
763
|
+
// Always release the lock
|
|
764
|
+
$lock->release();
|
|
765
|
+
}
|
|
766
|
+
} else {
|
|
767
|
+
// Could not acquire lock - another process is creating the order
|
|
768
|
+
Log::info('[ORDER CREATION]: Could not acquire lock, another process is creating order', [
|
|
769
|
+
'checkout_id' => $checkout->public_id,
|
|
770
|
+
]);
|
|
771
|
+
|
|
772
|
+
// Wait briefly and return the order that should be created by the other process
|
|
773
|
+
sleep(2);
|
|
774
|
+
$checkout->refresh();
|
|
775
|
+
|
|
776
|
+
if ($checkout->order) {
|
|
777
|
+
Log::info('[ORDER CREATION]: Order found after waiting for lock', [
|
|
778
|
+
'checkout_id' => $checkout->public_id,
|
|
779
|
+
'order_id' => $checkout->order->public_id,
|
|
780
|
+
]);
|
|
781
|
+
|
|
782
|
+
return $checkout->order;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
Log::warning('[ORDER CREATION]: Lock wait completed but no order found', [
|
|
786
|
+
'checkout_id' => $checkout->public_id,
|
|
787
|
+
]);
|
|
788
|
+
|
|
789
|
+
return null;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
/**
|
|
794
|
+
* Process a cart item.
|
|
677
795
|
*
|
|
678
|
-
* @param mixed $cartItem the cart item
|
|
796
|
+
* @param mixed $cartItem the cart item
|
|
679
797
|
* @param mixed $payload the payload
|
|
680
798
|
* @param mixed $customer the customer
|
|
681
799
|
*
|
|
@@ -727,6 +845,14 @@ class CheckoutController extends Controller
|
|
|
727
845
|
$destination = $serviceQuote ? $serviceQuote->getMeta('destination') : null;
|
|
728
846
|
$cart = $checkout->cart;
|
|
729
847
|
|
|
848
|
+
// If the checkout already has an order created
|
|
849
|
+
if ($checkout->order_uuid) {
|
|
850
|
+
$completedOrder = Order::where('uuid', $checkout->order_uuid)->first();
|
|
851
|
+
if ($completedOrder) {
|
|
852
|
+
return new OrderResource($completedOrder);
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
|
|
730
856
|
// if cart is null then cart has either been deleted or expired
|
|
731
857
|
if (!$cart) {
|
|
732
858
|
return response()->apiError('Cart expired');
|
|
@@ -1046,6 +1172,14 @@ class CheckoutController extends Controller
|
|
|
1046
1172
|
$amount = static::calculateCheckoutAmount($cart, $serviceQuote, $checkout->options);
|
|
1047
1173
|
$currency = $checkout->currency ?? $cart->getCurrency();
|
|
1048
1174
|
|
|
1175
|
+
// If the checkout already has an order created
|
|
1176
|
+
if ($checkout->order_uuid) {
|
|
1177
|
+
$completedOrder = Order::where('uuid', $checkout->order_uuid)->first();
|
|
1178
|
+
if ($completedOrder) {
|
|
1179
|
+
return new OrderResource($completedOrder);
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1049
1183
|
if (!$about) {
|
|
1050
1184
|
return response()->apiError('No network in request to capture order!');
|
|
1051
1185
|
}
|
|
@@ -1340,6 +1474,145 @@ class CheckoutController extends Controller
|
|
|
1340
1474
|
{
|
|
1341
1475
|
}
|
|
1342
1476
|
|
|
1477
|
+
/**
|
|
1478
|
+
* Get checkout status including payment and order details.
|
|
1479
|
+
*
|
|
1480
|
+
* This endpoint allows the app to query the current status of a checkout session,
|
|
1481
|
+
* including payment confirmation and order details. If payment is confirmed but
|
|
1482
|
+
* order doesn't exist (callback failed), it will create the order as a fallback.
|
|
1483
|
+
*
|
|
1484
|
+
* @return \Illuminate\Http\JsonResponse
|
|
1485
|
+
*/
|
|
1486
|
+
public function getCheckoutStatus(Request $request)
|
|
1487
|
+
{
|
|
1488
|
+
$checkoutId = $request->input('checkout');
|
|
1489
|
+
$token = $request->input('token');
|
|
1490
|
+
|
|
1491
|
+
// Validate required parameters
|
|
1492
|
+
if (!$checkoutId || !$token) {
|
|
1493
|
+
return response()->json([
|
|
1494
|
+
'error' => 'Missing required parameters: checkout and token',
|
|
1495
|
+
], 400);
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1498
|
+
try {
|
|
1499
|
+
// Find checkout by ID and token
|
|
1500
|
+
$checkout = Checkout::where('public_id', $checkoutId)
|
|
1501
|
+
->where('token', $token)
|
|
1502
|
+
->with(['order'])
|
|
1503
|
+
->first();
|
|
1504
|
+
|
|
1505
|
+
if (!$checkout) {
|
|
1506
|
+
return response()->json([
|
|
1507
|
+
'error' => 'Checkout not found',
|
|
1508
|
+
], 404);
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
// Initialize response (gateway-agnostic)
|
|
1512
|
+
$response = [
|
|
1513
|
+
'status' => $checkout->captured ? 'completed' : 'pending',
|
|
1514
|
+
'checkout' => $checkout->public_id,
|
|
1515
|
+
'payment' => null,
|
|
1516
|
+
'order' => $checkout->order ? new OrderResource($checkout->order) : null,
|
|
1517
|
+
];
|
|
1518
|
+
|
|
1519
|
+
// Check if this is a QPay checkout
|
|
1520
|
+
if ($checkout->gateway_uuid) {
|
|
1521
|
+
$gateway = Gateway::where('uuid', $checkout->gateway_uuid)->first();
|
|
1522
|
+
|
|
1523
|
+
if ($gateway && $gateway->code === 'qpay') {
|
|
1524
|
+
// Get QPay invoice ID from checkout options
|
|
1525
|
+
$qpayInvoiceId = $checkout->getOption('qpay_invoice_id');
|
|
1526
|
+
$payment = null;
|
|
1527
|
+
|
|
1528
|
+
if ($qpayInvoiceId) {
|
|
1529
|
+
// Create QPay instance with correct credentials
|
|
1530
|
+
$qpay = QPay::instance(
|
|
1531
|
+
$gateway->config->username,
|
|
1532
|
+
$gateway->config->password,
|
|
1533
|
+
$gateway->callback_url
|
|
1534
|
+
);
|
|
1535
|
+
|
|
1536
|
+
if ($gateway->sandbox) {
|
|
1537
|
+
$qpay->useSandbox();
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
$qpay->setAuthToken();
|
|
1541
|
+
|
|
1542
|
+
// Verify payment status with QPay
|
|
1543
|
+
$paymentCheck = $qpay->paymentCheck($qpayInvoiceId);
|
|
1544
|
+
$payment = data_get($paymentCheck, 'rows.0');
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
if ($payment && $payment->payment_status === 'PAID') {
|
|
1548
|
+
$response['status'] = 'paid';
|
|
1549
|
+
$response['payment'] = [
|
|
1550
|
+
'payment_id' => $payment->payment_id,
|
|
1551
|
+
'payment_status' => $payment->payment_status,
|
|
1552
|
+
'payment_amount' => $payment->payment_amount,
|
|
1553
|
+
'payment_date' => $payment->payment_date ?? null,
|
|
1554
|
+
'payment_wallet' => $payment->payment_wallet ?? 'QPay',
|
|
1555
|
+
];
|
|
1556
|
+
|
|
1557
|
+
// FALLBACK: If payment confirmed but order doesn't exist, create it
|
|
1558
|
+
if (!$checkout->order_uuid) {
|
|
1559
|
+
Log::info('[CHECKOUT STATUS FALLBACK]: Payment confirmed but no order exists, attempting to create', [
|
|
1560
|
+
'checkout_id' => $checkout->public_id,
|
|
1561
|
+
'payment_id' => $payment->payment_id,
|
|
1562
|
+
]);
|
|
1563
|
+
|
|
1564
|
+
$transactionDetails = [
|
|
1565
|
+
'transaction_id' => $payment->payment_id,
|
|
1566
|
+
'payment_status' => 'PAID',
|
|
1567
|
+
'payment_wallet' => $payment->payment_wallet ?? 'QPay',
|
|
1568
|
+
];
|
|
1569
|
+
|
|
1570
|
+
try {
|
|
1571
|
+
// Use the reusable gateway-agnostic method to create order
|
|
1572
|
+
// createOrderFromCheckout has built-in idempotency checks
|
|
1573
|
+
$order = $this->createOrderFromCheckout($checkout, $transactionDetails);
|
|
1574
|
+
|
|
1575
|
+
if ($order) {
|
|
1576
|
+
$response['status'] = 'completed';
|
|
1577
|
+
$response['order'] = new OrderResource($order);
|
|
1578
|
+
}
|
|
1579
|
+
} catch (\Exception $e) {
|
|
1580
|
+
// If order creation fails (e.g., race condition), refresh and check again
|
|
1581
|
+
Log::warning('[CHECKOUT STATUS FALLBACK]: Order creation failed, checking if order was created by another request', [
|
|
1582
|
+
'checkout_id' => $checkout->public_id,
|
|
1583
|
+
'error' => $e->getMessage(),
|
|
1584
|
+
]);
|
|
1585
|
+
|
|
1586
|
+
$checkout->refresh();
|
|
1587
|
+
if ($checkout->order_uuid) {
|
|
1588
|
+
// Order was created by another request
|
|
1589
|
+
$response['status'] = 'completed';
|
|
1590
|
+
$response['order'] = new OrderResource($checkout->order);
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
} else {
|
|
1594
|
+
// Order already exists
|
|
1595
|
+
$response['status'] = 'completed';
|
|
1596
|
+
$response['order'] = new OrderResource($checkout->order);
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1602
|
+
return response()->json($response);
|
|
1603
|
+
} catch (\Exception $e) {
|
|
1604
|
+
Log::error('[CHECKOUT STATUS ERROR]: ' . $e->getMessage(), [
|
|
1605
|
+
'checkout_id' => $checkoutId,
|
|
1606
|
+
'exception' => $e->getTraceAsString(),
|
|
1607
|
+
]);
|
|
1608
|
+
|
|
1609
|
+
return response()->json([
|
|
1610
|
+
'error' => 'Failed to retrieve checkout status',
|
|
1611
|
+
'message' => $e->getMessage(),
|
|
1612
|
+
], 500);
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1343
1616
|
/**
|
|
1344
1617
|
* Calculates the total checkout amount.
|
|
1345
1618
|
*
|
|
@@ -84,7 +84,7 @@ class CustomerController extends Controller
|
|
|
84
84
|
$q->orWhere('meta', 'not like', '%related_orders%');
|
|
85
85
|
});
|
|
86
86
|
}
|
|
87
|
-
});
|
|
87
|
+
}, true);
|
|
88
88
|
|
|
89
89
|
return OrderResource::collection($results);
|
|
90
90
|
}
|
|
@@ -104,7 +104,7 @@ class CustomerController extends Controller
|
|
|
104
104
|
|
|
105
105
|
$results = Place::queryWithRequest($request, function (&$query) use ($customer) {
|
|
106
106
|
$query->where('owner_uuid', $customer->uuid);
|
|
107
|
-
});
|
|
107
|
+
}, true);
|
|
108
108
|
|
|
109
109
|
return PlaceResource::collection($results);
|
|
110
110
|
}
|
|
@@ -951,4 +951,95 @@ class CustomerController extends Controller
|
|
|
951
951
|
|
|
952
952
|
return response()->apiError('An uknown error occured attempting to close customer account.');
|
|
953
953
|
}
|
|
954
|
+
|
|
955
|
+
/**
|
|
956
|
+
* Sends a verification code to the customer's phone for verification.
|
|
957
|
+
*
|
|
958
|
+
* @return \Illuminate\Http\JsonResponse
|
|
959
|
+
*/
|
|
960
|
+
public function requestPhoneVerification(Request $request)
|
|
961
|
+
{
|
|
962
|
+
$customer = Storefront::getCustomerFromToken();
|
|
963
|
+
$phone = static::phone($request->input('phone'));
|
|
964
|
+
|
|
965
|
+
if (!$customer) {
|
|
966
|
+
return response()->apiError('Not authorized to request phone verification.');
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
// Use the user associated with the contact
|
|
970
|
+
$user = User::where(['uuid' => $customer->user_uuid])->first();
|
|
971
|
+
if (!$user) {
|
|
972
|
+
return response()->apiError('No user associated with this customer.');
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
// Check if phone number is already used by another user
|
|
976
|
+
$existingUser = User::where('phone', $phone)
|
|
977
|
+
->where('uuid', '!=', $user->uuid)
|
|
978
|
+
->whereNull('deleted_at')
|
|
979
|
+
->withoutGlobalScopes()
|
|
980
|
+
->first();
|
|
981
|
+
|
|
982
|
+
if ($existingUser) {
|
|
983
|
+
return response()->apiError('This phone number is already associated with another account.');
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
$about = Storefront::about();
|
|
987
|
+
|
|
988
|
+
try {
|
|
989
|
+
VerificationCode::generateSmsVerificationFor($user, 'storefront_verify_phone', [
|
|
990
|
+
'messageCallback' => function ($verification) use ($about) {
|
|
991
|
+
return "Your {$about->name} verification code is {$verification->code}";
|
|
992
|
+
},
|
|
993
|
+
'meta' => ['phone' => $phone], // Store the phone number in meta
|
|
994
|
+
]);
|
|
995
|
+
|
|
996
|
+
return response()->json(['status' => 'ok']);
|
|
997
|
+
} catch (\Exception $e) {
|
|
998
|
+
return response()->apiError($e->getMessage());
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
/**
|
|
1003
|
+
* Verifies the phone number using the provided code.
|
|
1004
|
+
*
|
|
1005
|
+
* @return Customer
|
|
1006
|
+
*/
|
|
1007
|
+
public function verifyPhoneNumber(Request $request)
|
|
1008
|
+
{
|
|
1009
|
+
$customer = Storefront::getCustomerFromToken();
|
|
1010
|
+
$code = $request->input('code');
|
|
1011
|
+
|
|
1012
|
+
if (!$customer) {
|
|
1013
|
+
return response()->apiError('Not authorized to verify phone number.');
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
$user = $customer->user;
|
|
1017
|
+
|
|
1018
|
+
if (!$user) {
|
|
1019
|
+
return response()->apiError('No user associated with this customer.');
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
// Find the verification code
|
|
1023
|
+
$verificationCode = VerificationCode::where([
|
|
1024
|
+
'subject_uuid' => $user->uuid,
|
|
1025
|
+
'code' => $code,
|
|
1026
|
+
'for' => 'storefront_verify_phone',
|
|
1027
|
+
])->first();
|
|
1028
|
+
|
|
1029
|
+
if (!$verificationCode) {
|
|
1030
|
+
return response()->apiError('Invalid verification code!');
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
// Get the phone number from meta
|
|
1034
|
+
$phone = $verificationCode->meta['phone'];
|
|
1035
|
+
|
|
1036
|
+
// Update user and contact
|
|
1037
|
+
$user->update(['phone' => $phone, 'phone_verified_at' => now()]);
|
|
1038
|
+
$customer->update(['phone' => $phone]);
|
|
1039
|
+
|
|
1040
|
+
// Invalidate the verification code
|
|
1041
|
+
$verificationCode->delete();
|
|
1042
|
+
|
|
1043
|
+
return new Customer($customer->fresh());
|
|
1044
|
+
}
|
|
954
1045
|
}
|
|
@@ -41,7 +41,6 @@ class ServiceQuoteController extends Controller
|
|
|
41
41
|
$serviceType = $request->input('service_type');
|
|
42
42
|
$cart = Cart::retrieve($request->input('cart'));
|
|
43
43
|
$currency = $cart->currency;
|
|
44
|
-
$config = $request->input('config', 'storefront');
|
|
45
44
|
$all = $request->boolean('all');
|
|
46
45
|
$isRouteOptimized = $request->boolean('is_route_optimized', true);
|
|
47
46
|
$isNetwork = Str::startsWith(session('storefront_key'), 'network_');
|
|
@@ -106,7 +105,13 @@ class ServiceQuoteController extends Controller
|
|
|
106
105
|
$orderConfigKey = data_get($orderConfig, 'key', 'storefront');
|
|
107
106
|
|
|
108
107
|
// get service rates for config type
|
|
109
|
-
$serviceRates = ServiceRate::where(['company_uuid' => session('company'), 'service_type' => $orderConfigKey])->get();
|
|
108
|
+
// $serviceRates = ServiceRate::where(['company_uuid' => session('company'), 'service_type' => $orderConfigKey])->get();
|
|
109
|
+
$serviceRates = ServiceRate::getServicableForPlaces([$destination], $orderConfigKey, $currency, function ($q) {
|
|
110
|
+
$q->where('company_uuid', session('company'));
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// Convert to collection
|
|
114
|
+
$serviceRates = collect($serviceRates);
|
|
110
115
|
|
|
111
116
|
// if no service rates send an empty quote
|
|
112
117
|
if ($serviceRates->isEmpty()) {
|
|
@@ -200,7 +205,6 @@ class ServiceQuoteController extends Controller
|
|
|
200
205
|
$serviceType = $request->input('service_type');
|
|
201
206
|
$cart = Cart::retrieve($request->input('cart'));
|
|
202
207
|
$currency = $cart->currency;
|
|
203
|
-
$config = $request->input('config', 'storefront');
|
|
204
208
|
$all = $request->boolean('all');
|
|
205
209
|
$isRouteOptimized = $request->boolean('is_route_optimized', true);
|
|
206
210
|
|
|
@@ -294,7 +298,13 @@ class ServiceQuoteController extends Controller
|
|
|
294
298
|
$orderConfigKey = data_get($orderConfig, 'key', 'storefront');
|
|
295
299
|
|
|
296
300
|
// get service rates for config type
|
|
297
|
-
$serviceRates = ServiceRate::where(['company_uuid' => session('company'), 'service_type' => $orderConfigKey])->get();
|
|
301
|
+
// $serviceRates = ServiceRate::where(['company_uuid' => session('company'), 'service_type' => $orderConfigKey])->get();
|
|
302
|
+
$serviceRates = ServiceRate::getServicableForPlaces([$destination], $orderConfigKey, $currency, function ($q) {
|
|
303
|
+
$q->where('company_uuid', session('company'));
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
// Convert to collection
|
|
307
|
+
$serviceRates = collect($serviceRates);
|
|
298
308
|
|
|
299
309
|
// if no service rates send an empty quote
|
|
300
310
|
if ($serviceRates->isEmpty()) {
|
package/server/src/routes.php
CHANGED
|
@@ -54,6 +54,7 @@ Route::prefix(config('storefront.api.routing.prefix', 'storefront'))->namespace(
|
|
|
54
54
|
// storefront/v1/checkouts
|
|
55
55
|
$router->group(['prefix' => 'checkouts'], function () use ($router) {
|
|
56
56
|
$router->get('before', 'CheckoutController@beforeCheckout');
|
|
57
|
+
$router->get('status', 'CheckoutController@getCheckoutStatus');
|
|
57
58
|
$router->post('capture', 'CheckoutController@captureOrder');
|
|
58
59
|
$router->post('stripe-setup-intent', 'CheckoutController@createStripeSetupIntentForCustomer');
|
|
59
60
|
$router->put('stripe-update-payment-intent', 'CheckoutController@updateStripePaymentIntent');
|
|
@@ -118,6 +119,8 @@ Route::prefix(config('storefront.api.routing.prefix', 'storefront'))->namespace(
|
|
|
118
119
|
$router->post('stripe-setup-intent', 'CustomerController@getStripeSetupIntent');
|
|
119
120
|
$router->post('account-closure', 'CustomerController@startAccountClosure');
|
|
120
121
|
$router->post('confirm-account-closure', 'CustomerController@confirmAccountClosure');
|
|
122
|
+
$router->post('request-phone-verification', 'CustomerController@requestPhoneVerification');
|
|
123
|
+
$router->post('verify-phone-number', 'CustomerController@verifyPhoneNumber');
|
|
121
124
|
});
|
|
122
125
|
|
|
123
126
|
// hotfix! storefront-app sending customer update to /contacts/ route
|