Skip to content

Commit

Permalink
[ADD] One Click Checkout.
Browse files Browse the repository at this point in the history
  • Loading branch information
Seiger committed Feb 10, 2025
1 parent 3ffc077 commit c92ae5f
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 3 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ of Evolution CMS for seamless and efficient **online commerce**.
- [ ] Customer Reviews and Ratings.
- [ ] Wishlist and Favorites.
- [x] Checkout.
- [x] One Click Checkout.
- [ ] Promo Code System.
- [x] Plugin events.
- [x] sCommerceManagerAddTabEvent.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ public function up(): void
$table->decimal('cost', 9, 2)->default(0)->comment('Total order amount');
$table->char('currency', 3)->default('USD')->comment('Currency cost this order');
$table->unsignedInteger('status')->default(1)->comment('Order status (1: new)');
$table->boolean('is_quick')->default(false)->comment('Flag indicating if the order is a quick purchase');
$table->boolean('do_not_call')->default(false)->comment('"Do not call back" option');
$table->text('comment')->nullable()->comment('Comment on the order');
$table->string('lang', 10)->index()->default('base');
Expand Down
1 change: 1 addition & 0 deletions docs/pages/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ of Evolution CMS for seamless and efficient **online commerce**.
- [ ] Customer Reviews and Ratings.
- [ ] Wishlist and Favorites.
- [x] Checkout.
- [x] One Click Checkout.
- [ ] Promo Code System.
- [x] Plugin events.
- [x] sCommerceManagerAddTabEvent.
Expand Down
132 changes: 131 additions & 1 deletion src/Checkout/sCheckout.php
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ public function processOrder(): array

$order = $this->saveOrder();

evo()->logEvent(0, 1, "Замовлення #{$order->id} успішно створено.", 'sCommerce: Order Created');
evo()->logEvent(0, 1, "Order #{$order->id} successfully created.", 'sCommerce: Order Created');
Log::info("Order #{$order->id} successfully created.", ['order_id' => $order->id, 'total_cost' => $order->cost, 'user_id' => $order->user_id]);

unset($_SESSION['sCheckout'], $_SESSION['sCart']);
Expand All @@ -440,6 +440,136 @@ public function processOrder(): array
}
}

/**
* Process the quick order.
*
* This method validates the input data, creates a new order for a quick purchase,
* and saves it in the database. If product is 0, it will fetch products from the cart.
*
* @param array $data The data from the request, including product_id, quantity, user_phone, and/or user_email.
* @return array An array containing the result of the operation with success status and a message.
*/
public static function quickOrder(array $data)
{
$validator = Validator::make($data, [
'product' => 'nullable|integer|exists:products,id,' . ((int)$data['productId'] == 0 ? '0' : null),
'quantity' => 'nullable|integer|min:1',
'phone' => 'nullable|string|max:20',
'email' => 'nullable|email|max:255',
]);

if (empty($data['phone']) && empty($data['email'])) {
return [
'success' => false,
'message' => 'Either phone number or email is required.',
];
}

if ($validator->fails()) {
return [
'success' => false,
'message' => 'Invalid data provided.',
'errors' => $validator->errors(),
];
}

$userId = evo()->getLoginUserID('web') ?: evo()->getLoginUserID('mgr'); // Checking if the user is authorized
$user = evo()->getUserInfo($userId ?: 0) ?: [];
$user = array_merge($user, evo()->getUserSettings());

$userData = [
'id' => $user['id'] ?? 0,
'name' => $user['fullname'] ?? '',
'email' => $user['email'] ?? ($data['email'] ?? ''),
'phone' => $user['phone'] ?? ($data['phone'] ?? ''),
'address' => [
'country' => $user['country'] ?? '',
'state' => $user['state'] ?? '',
'city' => $user['city'] ?? '',
'street' => $user['street'] ?? '',
'zip' => $user['zip'] ?? '',
],
];

if (empty($data['productId']) || $data['productId'] == 0) {
$cartData = sCart::getMiniCart();
if (empty($cartData['items'])) {
return [
'success' => false,
'message' => 'Cart is empty. Cannot create a quick order.',
];
}

$productsData = $cartData['items'];
$cost = $cartData['totalSum'];
} else {
$product = sCommerce::getProduct($data['productId']);
if (!$product) {
return [
'success' => false,
'message' => 'Product not found.',
];
}

$quantity = isset($data['quantity']) && $data['quantity'] > 0 ? (int) $data['quantity'] : 1;
$price = sCommerce::convertPriceNumber($product->price, $product->currency, sCommerce::currentCurrency());
$cost = $price * $quantity;

$productsData = [
[
'id' => $product->id,
'title' => $product->title,
'link' => $product->link,
'coverSrc' => $product->coverSrc,
'category' => $product->category,
'sku' => $product->sku,
'inventory' => $product->inventory,
'price' => $product->price,
'oldPrice' => $product->oldPrice,
'quantity' => $quantity,
]
];
}

do {
$identifier = Str::random(rand(32, 64));
} while (sOrder::where('identifier', $identifier)->exists());

$adminNotes = [
[
'comment' => "Quick order created by user " . implode(' ', [trim($userData['name']), trim($userData['phone']), trim($userData['email'])]) . '.',
'timestamp' => now(),
'user_id' => (int)$userData['id'],
]
];

$order = new sOrder();
$order->user_id = (int)$userData['id'];
$order->identifier = $identifier;
$order->user_info = json_encode($userData, JSON_UNESCAPED_UNICODE);
$order->products = json_encode($productsData, JSON_UNESCAPED_UNICODE);
$order->cost = $cost;
$order->currency = sCommerce::currentCurrency();
$order->is_quick = true;
$order->admin_notes = json_encode([
'purchase_link' => back()->getTargetUrl(),
], JSON_UNESCAPED_UNICODE);
$order->save();

if ($data['productId'] == 0) {
unset($_SESSION['sCheckout'], $_SESSION['sCart']);
}

evo()->logEvent(0, 1, "Order #{$order->id} successfully created.", 'sCommerce: Order By Click Created');
Log::info("Order By Click #{$order->id} successfully created.", ['order_id' => $order->id, 'total_cost' => $order->cost, 'user_id' => $order->user_id]);

return [
'success' => true,
'message' => __('sCommerce::order.success'),
'order' => $order,
];
}

/**
* Register a delivery method.
*
Expand Down
4 changes: 4 additions & 0 deletions src/Http/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,8 @@
sCheckout::processOrder(),
fn($result) => response()->json($result, $result['success'] === true ? 200 : 422)
))->name('processOrder');
Route::post('quick-order', fn() => tap(
sCheckout::quickOrder(request()->all()),
fn($result) => response()->json($result, $result['success'] === true ? 200 : 422)
))->name('quickOrder');
});
4 changes: 2 additions & 2 deletions src/Models/sOrder.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ class sOrder extends Model
const PAYMENT_STATUS_CANCELED = 9; // Оплату скасовано
const PAYMENT_STATUS_REJECTED = 10; // Оплату відхилено
const PAYMENT_STATUS_AUTHORIZED = 11; // Авторизовано (очікує списання)
const PAYMENT_STATUS_EXPIRED = 12; // Термін дії платежу минув
const PAYMENT_STATUS_PENDING_VERIFICATION = 13; // Очікує верифікації
const PAYMENT_STATUS_PENDING_VERIFICATION = 12; // Очікує верифікації
const PAYMENT_STATUS_EXPIRED = 13; // Термін дії платежу минув

/**
* Cast attributes to specific types.
Expand Down
34 changes: 34 additions & 0 deletions views/scripts/cart.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
trigger = 'buy';
addToCart(e, productId, quantity, trigger);
break;
case Boolean(e.target.closest('[data-sFastBuy]')?.hasAttribute("data-sFastBuy")):
productId = parseInt(e.target.closest('[data-sFastBuy]').getAttribute('data-sFastBuy'));
inputs = e.target.closest('[data-sFastBuy]').parentNode.querySelectorAll('input');
quickOrder(e, productId, inputs);
break;
case Boolean(e.target.closest('[data-sRemove]')?.hasAttribute("data-sRemove")):
productId = parseInt(e.target.closest('[data-sRemove]').getAttribute('data-sRemove'));
removeFromCart(e, productId);
Expand Down Expand Up @@ -56,6 +61,35 @@ function addToCart(e, productId, quantity, trigger) {
e.target.disabled = false;
});
}
function quickOrder(e, productId, inputs) {
e.preventDefault();
e.target.disabled = true;
let form = new FormData();
form.append('productId', productId);
inputs.forEach((input) => {
form.append(input.name, input.value);
});
fetch('{{route('sCommerce.quickOrder')}}', {
method: "post",
cache: "no-store",
headers: {"X-Requested-With": "XMLHttpRequest"},
body: form
}).then((response) => {
return response.json();
}).then((data) => {
document.dispatchEvent(new CustomEvent('sCommerceAddedQuickOrder', {detail: data}));
e.target.disabled = false;
}).catch(function(error) {
if (error === 'SyntaxError: Unexpected token < in JSON at position 0') {
console.error('Request failed SyntaxError: The response must contain a JSON string.');
} else {
console.error('Request failed', error, '.');
}
e.target.disabled = false;
});
}
function removeFromCart(e, productId) {
e.preventDefault();
e.target.disabled = true;
Expand Down

0 comments on commit c92ae5f

Please sign in to comment.